@dependabit/monitor 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.
Files changed (69) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +33 -0
  4. package/dist/checkers/github-repo.d.ts +17 -0
  5. package/dist/checkers/github-repo.d.ts.map +1 -0
  6. package/dist/checkers/github-repo.js +115 -0
  7. package/dist/checkers/github-repo.js.map +1 -0
  8. package/dist/checkers/index.d.ts +7 -0
  9. package/dist/checkers/index.d.ts.map +1 -0
  10. package/dist/checkers/index.js +7 -0
  11. package/dist/checkers/index.js.map +1 -0
  12. package/dist/checkers/openapi.d.ts +24 -0
  13. package/dist/checkers/openapi.d.ts.map +1 -0
  14. package/dist/checkers/openapi.js +221 -0
  15. package/dist/checkers/openapi.js.map +1 -0
  16. package/dist/checkers/url-content.d.ts +16 -0
  17. package/dist/checkers/url-content.d.ts.map +1 -0
  18. package/dist/checkers/url-content.js +66 -0
  19. package/dist/checkers/url-content.js.map +1 -0
  20. package/dist/comparator.d.ts +16 -0
  21. package/dist/comparator.d.ts.map +1 -0
  22. package/dist/comparator.js +53 -0
  23. package/dist/comparator.js.map +1 -0
  24. package/dist/index.d.ts +15 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +12 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/monitor.d.ts +43 -0
  29. package/dist/monitor.d.ts.map +1 -0
  30. package/dist/monitor.js +85 -0
  31. package/dist/monitor.js.map +1 -0
  32. package/dist/normalizer.d.ts +24 -0
  33. package/dist/normalizer.d.ts.map +1 -0
  34. package/dist/normalizer.js +97 -0
  35. package/dist/normalizer.js.map +1 -0
  36. package/dist/scheduler.d.ts +64 -0
  37. package/dist/scheduler.d.ts.map +1 -0
  38. package/dist/scheduler.js +132 -0
  39. package/dist/scheduler.js.map +1 -0
  40. package/dist/severity.d.ts +22 -0
  41. package/dist/severity.d.ts.map +1 -0
  42. package/dist/severity.js +87 -0
  43. package/dist/severity.js.map +1 -0
  44. package/dist/types.d.ts +36 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/types.js +5 -0
  47. package/dist/types.js.map +1 -0
  48. package/package.json +39 -0
  49. package/src/checkers/github-repo.ts +150 -0
  50. package/src/checkers/index.ts +7 -0
  51. package/src/checkers/openapi.ts +310 -0
  52. package/src/checkers/url-content.ts +78 -0
  53. package/src/comparator.ts +68 -0
  54. package/src/index.ts +20 -0
  55. package/src/monitor.ts +120 -0
  56. package/src/normalizer.ts +122 -0
  57. package/src/scheduler.ts +175 -0
  58. package/src/severity.ts +112 -0
  59. package/src/types.ts +40 -0
  60. package/test/checkers/github-repo.test.ts +124 -0
  61. package/test/checkers/openapi.test.ts +352 -0
  62. package/test/checkers/url-content.test.ts +99 -0
  63. package/test/comparator.test.ts +108 -0
  64. package/test/monitor.test.ts +177 -0
  65. package/test/normalizer.test.ts +66 -0
  66. package/test/scheduler.test.ts +674 -0
  67. package/test/severity.test.ts +122 -0
  68. package/tsconfig.json +10 -0
  69. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,108 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { StateComparator } from '../src/comparator.js';
3
+
4
+ describe('StateComparator', () => {
5
+ let comparator: StateComparator;
6
+
7
+ beforeEach(() => {
8
+ comparator = new StateComparator();
9
+ });
10
+
11
+ describe('compare', () => {
12
+ it('should detect state hash changes', () => {
13
+ const oldState = {
14
+ stateHash: 'abc123',
15
+ version: 'v1.0.0',
16
+ fetchedAt: new Date('2024-01-01')
17
+ };
18
+
19
+ const newState = {
20
+ stateHash: 'def456',
21
+ version: 'v1.0.0',
22
+ fetchedAt: new Date('2024-01-02')
23
+ };
24
+
25
+ const result = comparator.compare(oldState, newState);
26
+
27
+ expect(result.hasChanged).toBe(true);
28
+ expect(result.changes).toContain('stateHash');
29
+ });
30
+
31
+ it('should detect version changes', () => {
32
+ const oldState = {
33
+ stateHash: 'abc123',
34
+ version: 'v1.0.0',
35
+ fetchedAt: new Date('2024-01-01')
36
+ };
37
+
38
+ const newState = {
39
+ stateHash: 'abc123',
40
+ version: 'v2.0.0',
41
+ fetchedAt: new Date('2024-01-02')
42
+ };
43
+
44
+ const result = comparator.compare(oldState, newState);
45
+
46
+ expect(result.hasChanged).toBe(true);
47
+ expect(result.changes).toContain('version');
48
+ });
49
+
50
+ it('should return no change when states match', () => {
51
+ const oldState = {
52
+ stateHash: 'abc123',
53
+ version: 'v1.0.0',
54
+ fetchedAt: new Date('2024-01-01')
55
+ };
56
+
57
+ const newState = {
58
+ stateHash: 'abc123',
59
+ version: 'v1.0.0',
60
+ fetchedAt: new Date('2024-01-02')
61
+ };
62
+
63
+ const result = comparator.compare(oldState, newState);
64
+
65
+ expect(result.hasChanged).toBe(false);
66
+ expect(result.changes).toHaveLength(0);
67
+ });
68
+
69
+ it('should detect multiple changes', () => {
70
+ const oldState = {
71
+ stateHash: 'abc123',
72
+ version: 'v1.0.0',
73
+ metadata: { author: 'Alice' },
74
+ fetchedAt: new Date('2024-01-01')
75
+ };
76
+
77
+ const newState = {
78
+ stateHash: 'def456',
79
+ version: 'v2.0.0',
80
+ metadata: { author: 'Bob' },
81
+ fetchedAt: new Date('2024-01-02')
82
+ };
83
+
84
+ const result = comparator.compare(oldState, newState);
85
+
86
+ expect(result.hasChanged).toBe(true);
87
+ expect(result.changes.length).toBeGreaterThan(1);
88
+ });
89
+
90
+ it('should handle missing version in old state', () => {
91
+ const oldState = {
92
+ stateHash: 'abc123',
93
+ fetchedAt: new Date('2024-01-01')
94
+ };
95
+
96
+ const newState = {
97
+ stateHash: 'abc123',
98
+ version: 'v1.0.0',
99
+ fetchedAt: new Date('2024-01-02')
100
+ };
101
+
102
+ const result = comparator.compare(oldState, newState);
103
+
104
+ expect(result.hasChanged).toBe(true);
105
+ expect(result.changes).toContain('version');
106
+ });
107
+ });
108
+ });
@@ -0,0 +1,177 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { Monitor } from '../src/monitor.js';
3
+
4
+ // Mock global fetch to prevent real network calls
5
+ const mockFetch = vi.fn();
6
+ global.fetch = mockFetch as any;
7
+
8
+ describe('Monitor', () => {
9
+ let monitor: Monitor;
10
+
11
+ beforeEach(() => {
12
+ monitor = new Monitor();
13
+ vi.clearAllMocks();
14
+
15
+ // Mock successful fetch responses by default
16
+ mockFetch.mockImplementation((url: string) => {
17
+ // Fail for invalid URLs
18
+ if (url.includes('invalid-url')) {
19
+ return Promise.reject(new Error('Network error'));
20
+ }
21
+
22
+ // Success response
23
+ return Promise.resolve({
24
+ ok: true,
25
+ status: 200,
26
+ json: async () => ({
27
+ tag_name: 'v1.0.0',
28
+ name: 'Release v1.0.0',
29
+ published_at: '2024-01-01T00:00:00Z',
30
+ body: 'Release notes',
31
+ html_url: 'https://github.com/owner/repo/releases/v1.0.0'
32
+ }),
33
+ headers: {
34
+ get: (name: string) => (name === 'content-type' ? 'text/html' : null)
35
+ },
36
+ text: async () => '<html><body>Test content</body></html>'
37
+ });
38
+ });
39
+ });
40
+
41
+ describe('checkDependency', () => {
42
+ it('should check a single dependency and detect changes', async () => {
43
+ const dependency = {
44
+ id: 'test-id',
45
+ url: 'https://github.com/owner/repo',
46
+ type: 'reference-implementation' as const,
47
+ accessMethod: 'github-api' as const,
48
+ currentStateHash: 'old-hash'
49
+ };
50
+
51
+ const result = await monitor.checkDependency(dependency);
52
+
53
+ expect(result).toBeDefined();
54
+ expect(result.dependency).toEqual(dependency);
55
+ expect(result.hasChanged).toBeDefined();
56
+ });
57
+
58
+ it('should handle errors gracefully', async () => {
59
+ mockFetch.mockRejectedValue(new Error('Network error'));
60
+
61
+ const dependency = {
62
+ id: 'test-id',
63
+ url: 'https://invalid-url.com',
64
+ type: 'documentation' as const,
65
+ accessMethod: 'http' as const,
66
+ currentStateHash: 'old-hash'
67
+ };
68
+
69
+ const result = await monitor.checkDependency(dependency);
70
+
71
+ expect(result).toBeDefined();
72
+ expect(result.error).toBeDefined();
73
+ });
74
+
75
+ it('should use appropriate checker based on access method', async () => {
76
+ const githubDep = {
77
+ id: 'github-id',
78
+ url: 'https://github.com/owner/repo',
79
+ type: 'reference-implementation' as const,
80
+ accessMethod: 'github-api' as const,
81
+ currentStateHash: 'hash1'
82
+ };
83
+
84
+ const httpDep = {
85
+ id: 'http-id',
86
+ url: 'https://example.com/docs',
87
+ type: 'documentation' as const,
88
+ accessMethod: 'http' as const,
89
+ currentStateHash: 'hash2'
90
+ };
91
+
92
+ const result1 = await monitor.checkDependency(githubDep);
93
+ const result2 = await monitor.checkDependency(httpDep);
94
+
95
+ expect(result1).toBeDefined();
96
+ expect(result2).toBeDefined();
97
+ });
98
+ });
99
+
100
+ describe('checkAll', () => {
101
+ it('should check multiple dependencies in parallel', async () => {
102
+ const dependencies = [
103
+ {
104
+ id: 'dep1',
105
+ url: 'https://github.com/owner/repo1',
106
+ type: 'reference-implementation' as const,
107
+ accessMethod: 'github-api' as const,
108
+ currentStateHash: 'hash1'
109
+ },
110
+ {
111
+ id: 'dep2',
112
+ url: 'https://github.com/owner/repo2',
113
+ type: 'reference-implementation' as const,
114
+ accessMethod: 'github-api' as const,
115
+ currentStateHash: 'hash2'
116
+ }
117
+ ];
118
+
119
+ const results = await monitor.checkAll(dependencies);
120
+
121
+ expect(results).toHaveLength(2);
122
+ expect(results[0].dependency.id).toBe('dep1');
123
+ expect(results[1].dependency.id).toBe('dep2');
124
+ });
125
+
126
+ it('should handle mixed success and errors', async () => {
127
+ const dependencies = [
128
+ {
129
+ id: 'valid',
130
+ url: 'https://github.com/owner/repo',
131
+ type: 'reference-implementation' as const,
132
+ accessMethod: 'github-api' as const,
133
+ currentStateHash: 'hash1'
134
+ },
135
+ {
136
+ id: 'invalid',
137
+ url: 'https://invalid-url.com',
138
+ type: 'documentation' as const,
139
+ accessMethod: 'http' as const,
140
+ currentStateHash: 'hash2'
141
+ }
142
+ ];
143
+
144
+ const results = await monitor.checkAll(dependencies);
145
+
146
+ expect(results).toHaveLength(2);
147
+ expect(results.some((r) => !r.error)).toBe(true);
148
+ expect(results.some((r) => r.error)).toBe(true);
149
+ });
150
+
151
+ it('should respect monitoring rules', async () => {
152
+ const dependencies = [
153
+ {
154
+ id: 'enabled',
155
+ url: 'https://github.com/owner/repo',
156
+ type: 'reference-implementation' as const,
157
+ accessMethod: 'github-api' as const,
158
+ currentStateHash: 'hash1',
159
+ monitoring: { enabled: true }
160
+ },
161
+ {
162
+ id: 'disabled',
163
+ url: 'https://github.com/owner/repo2',
164
+ type: 'reference-implementation' as const,
165
+ accessMethod: 'github-api' as const,
166
+ currentStateHash: 'hash2',
167
+ monitoring: { enabled: false }
168
+ }
169
+ ];
170
+
171
+ const results = await monitor.checkAll(dependencies);
172
+
173
+ expect(results).toHaveLength(1);
174
+ expect(results[0].dependency.id).toBe('enabled');
175
+ });
176
+ });
177
+ });
@@ -0,0 +1,66 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { normalizeHTML } from '../src/normalizer.js';
3
+
4
+ describe('HTML Normalizer', () => {
5
+ describe('normalizeHTML', () => {
6
+ it('should remove script tags', () => {
7
+ const html = '<div>Content<script>alert("test")</script></div>';
8
+ const result = normalizeHTML(html);
9
+ expect(result).not.toContain('<script>');
10
+ expect(result).not.toContain('alert');
11
+ });
12
+
13
+ it('should remove style tags', () => {
14
+ const html = '<div>Content<style>.class { color: red; }</style></div>';
15
+ const result = normalizeHTML(html);
16
+ expect(result).not.toContain('<style>');
17
+ expect(result).not.toContain('color: red');
18
+ });
19
+
20
+ it('should strip HTML comments', () => {
21
+ const html = '<div>Content<!-- This is a comment --></div>';
22
+ const result = normalizeHTML(html);
23
+ expect(result).not.toContain('<!--');
24
+ expect(result).not.toContain('-->');
25
+ });
26
+
27
+ it('should normalize whitespace', () => {
28
+ const html = '<div>Content with multiple spaces</div>';
29
+ const result = normalizeHTML(html);
30
+ expect(result).toContain('Content with multiple spaces');
31
+ });
32
+
33
+ it('should remove timestamp patterns', () => {
34
+ const html = '<div>Updated: 2024-01-01 12:00:00</div><div>Last modified: Jan 1, 2024</div>';
35
+ const result = normalizeHTML(html);
36
+ expect(result).not.toContain('Updated:');
37
+ expect(result).not.toContain('Last modified:');
38
+ });
39
+
40
+ it('should remove analytics tracking parameters', () => {
41
+ const html = '<a href="https://example.com?utm_source=test&utm_campaign=ad">Link</a>';
42
+ const result = normalizeHTML(html);
43
+ expect(result).not.toContain('utm_source');
44
+ expect(result).not.toContain('utm_campaign');
45
+ });
46
+
47
+ it('should preserve meaningful content', () => {
48
+ const html = '<h1>API Documentation</h1><p>This is the main content.</p>';
49
+ const result = normalizeHTML(html);
50
+ expect(result).toContain('API Documentation');
51
+ expect(result).toContain('This is the main content');
52
+ });
53
+
54
+ it('should handle empty input', () => {
55
+ const result = normalizeHTML('');
56
+ expect(result).toBe('');
57
+ });
58
+
59
+ it('should produce consistent output', () => {
60
+ const html = '<div>Test<script>x()</script> </div>';
61
+ const result1 = normalizeHTML(html);
62
+ const result2 = normalizeHTML(html);
63
+ expect(result1).toBe(result2);
64
+ });
65
+ });
66
+ });