recker 1.0.79 → 1.0.80-next.70ea84d

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 (196) hide show
  1. package/dist/browser/browser/mini.d.ts +2 -2
  2. package/dist/browser/browser/recker-mini.d.ts +8 -8
  3. package/dist/browser/browser/recker.d.ts +11 -8
  4. package/dist/browser/browser/recker.js +54 -6
  5. package/dist/browser/core/client.d.ts +15 -10
  6. package/dist/browser/core/client.js +54 -38
  7. package/dist/browser/index.iife.min.js +129 -130
  8. package/dist/browser/index.min.js +129 -130
  9. package/dist/browser/index.mini.iife.js +5697 -636
  10. package/dist/browser/index.mini.iife.min.js +47 -48
  11. package/dist/browser/index.mini.min.js +47 -48
  12. package/dist/browser/index.mini.umd.js +5697 -636
  13. package/dist/browser/index.mini.umd.min.js +47 -48
  14. package/dist/browser/index.umd.min.js +129 -130
  15. package/dist/browser/mini.d.ts +2 -2
  16. package/dist/browser/plugins/proxy-rotator.d.ts +2 -2
  17. package/dist/browser/plugins/proxy-rotator.js +6 -28
  18. package/dist/browser/recker-mini.d.ts +8 -8
  19. package/dist/browser/recker.d.ts +11 -8
  20. package/dist/browser/recker.js +54 -6
  21. package/dist/browser/scrape/document.js +2 -2
  22. package/dist/browser/scrape/element.js +7 -1
  23. package/dist/browser/scrape/parser/nodes/html.js +1 -1
  24. package/dist/browser/scrape/spider.d.ts +52 -0
  25. package/dist/browser/scrape/spider.js +620 -38
  26. package/dist/browser/scrape/types.d.ts +2 -0
  27. package/dist/browser/search/google.d.ts +26 -1
  28. package/dist/browser/search/google.js +427 -45
  29. package/dist/browser/seo/analyzer.d.ts +1 -0
  30. package/dist/browser/seo/analyzer.js +144 -1
  31. package/dist/browser/seo/index.d.ts +1 -1
  32. package/dist/browser/seo/keyword-campaign-analyzer.d.ts +2 -0
  33. package/dist/browser/seo/keyword-campaign-analyzer.js +538 -0
  34. package/dist/browser/seo/keyword-campaign-seed-advanced.d.ts +17 -0
  35. package/dist/browser/seo/keyword-campaign-seed-advanced.js +269 -0
  36. package/dist/browser/seo/keyword-campaign-seed-core.d.ts +29 -0
  37. package/dist/browser/seo/keyword-campaign-seed-core.js +525 -0
  38. package/dist/browser/seo/keyword-campaign-shared.d.ts +165 -0
  39. package/dist/browser/seo/keyword-campaign-shared.js +59 -0
  40. package/dist/browser/seo/keyword-campaign.d.ts +4 -107
  41. package/dist/browser/seo/keyword-campaign.js +2 -380
  42. package/dist/browser/seo/keywords.js +5 -22
  43. package/dist/browser/seo/types.d.ts +19 -0
  44. package/dist/browser/transport/curl.d.ts +5 -1
  45. package/dist/browser/transport/curl.js +207 -50
  46. package/dist/browser/transport/undici.d.ts +4 -3
  47. package/dist/browser/transport/undici.js +123 -49
  48. package/dist/browser/types/index.d.ts +9 -3
  49. package/dist/browser/utils/binary-manager.js +26 -3
  50. package/dist/browser/utils/block-detector.d.ts +8 -0
  51. package/dist/browser/utils/block-detector.js +542 -7
  52. package/dist/cli/commands/hls-runner.js +5 -4
  53. package/dist/cli/commands/live-runner.js +5 -4
  54. package/dist/cli/commands/loadtest-runner.js +3 -2
  55. package/dist/cli/commands/search.d.ts +2 -0
  56. package/dist/cli/commands/search.js +105 -0
  57. package/dist/cli/commands/seo-runner.js +9 -7
  58. package/dist/cli/commands/seo.js +140 -1
  59. package/dist/cli/commands/serve.js +75 -131
  60. package/dist/cli/commands/server-runner.js +59 -82
  61. package/dist/cli/commands/spider-runner.d.ts +37 -1
  62. package/dist/cli/commands/spider-runner.js +134 -10
  63. package/dist/cli/commands/spider.d.ts +18 -1
  64. package/dist/cli/commands/spider.js +457 -27
  65. package/dist/cli/events/handlers/cli.js +30 -1
  66. package/dist/cli/events/handlers/tui.js +26 -0
  67. package/dist/cli/events/types.d.ts +27 -0
  68. package/dist/cli/handler.d.ts +2 -12
  69. package/dist/cli/handler.js +20 -15
  70. package/dist/cli/handlers/protocols.js +39 -12
  71. package/dist/cli/handlers/search.d.ts +2 -0
  72. package/dist/cli/handlers/search.js +171 -0
  73. package/dist/cli/handlers/seo-analyze.d.ts +1 -0
  74. package/dist/cli/handlers/seo-analyze.js +666 -0
  75. package/dist/cli/handlers/seo-robots.d.ts +1 -0
  76. package/dist/cli/handlers/seo-robots.js +76 -0
  77. package/dist/cli/handlers/seo-serp.d.ts +54 -0
  78. package/dist/cli/handlers/seo-serp.js +243 -0
  79. package/dist/cli/handlers/seo-sitemap.d.ts +1 -0
  80. package/dist/cli/handlers/seo-sitemap.js +55 -0
  81. package/dist/cli/handlers/seo-spider.d.ts +1 -0
  82. package/dist/cli/handlers/seo-spider.js +334 -0
  83. package/dist/cli/handlers/seo.d.ts +8 -4
  84. package/dist/cli/handlers/seo.js +294 -442
  85. package/dist/cli/handlers/spider.js +94 -17
  86. package/dist/cli/handlers/streaming.js +5 -1
  87. package/dist/cli/index.js +11 -2
  88. package/dist/cli/presets.d.ts +1 -1
  89. package/dist/cli/presets.js +15 -4
  90. package/dist/cli/tui/app.js +6 -1
  91. package/dist/cli/tui/components/rich-response.d.ts +72 -0
  92. package/dist/cli/tui/components/rich-response.js +117 -0
  93. package/dist/cli/tui/executor-commands/background.js +30 -24
  94. package/dist/cli/tui/executor-commands/testing.js +3 -2
  95. package/dist/cli/tui/hooks/useDomains.d.ts +17 -0
  96. package/dist/cli/tui/hooks/useHelp.js +15 -2
  97. package/dist/cli/tui/job-manager.d.ts +4 -4
  98. package/dist/cli/tui/job-manager.js +5 -1
  99. package/dist/cli/tui/spider-tui.d.ts +63 -0
  100. package/dist/cli/tui/spider-tui.js +120 -2
  101. package/dist/cli/types.d.ts +12 -0
  102. package/dist/cli/types.js +1 -0
  103. package/dist/cli/utils/option-helpers.d.ts +10 -0
  104. package/dist/cli/utils/option-helpers.js +63 -0
  105. package/dist/cli/utils/score-color.d.ts +11 -0
  106. package/dist/cli/utils/score-color.js +11 -0
  107. package/dist/cli/utils/serp-campaign.d.ts +53 -0
  108. package/dist/cli/utils/serp-campaign.js +53 -0
  109. package/dist/cli/utils/serp-config.d.ts +26 -0
  110. package/dist/cli/utils/serp-config.js +125 -0
  111. package/dist/core/client.d.ts +15 -10
  112. package/dist/core/client.js +54 -38
  113. package/dist/index.d.ts +1 -0
  114. package/dist/index.js +1 -0
  115. package/dist/mcp/cli.js +35 -34
  116. package/dist/mcp/client.d.ts +2 -2
  117. package/dist/mcp/client.js +20 -2
  118. package/dist/mcp/contract.d.ts +1 -1
  119. package/dist/mcp/profiles.js +5 -1
  120. package/dist/mcp/prompts/index.js +8 -4
  121. package/dist/mcp/resources/index.js +46 -23
  122. package/dist/mcp/server.js +9 -6
  123. package/dist/mcp/tools/protocols.js +9 -2
  124. package/dist/mcp/tools/registry.js +13 -3
  125. package/dist/mcp/tools/seo.js +427 -2
  126. package/dist/mcp/types.d.ts +5 -1
  127. package/dist/plugins/proxy-rotator.d.ts +2 -2
  128. package/dist/plugins/proxy-rotator.js +6 -28
  129. package/dist/raffel/client.d.ts +38 -0
  130. package/dist/raffel/client.js +282 -0
  131. package/dist/raffel/index.d.ts +2 -0
  132. package/dist/raffel/index.js +2 -0
  133. package/dist/raffel/types.d.ts +40 -0
  134. package/dist/raffel/types.js +14 -0
  135. package/dist/recker.d.ts +13 -7
  136. package/dist/recker.js +58 -6
  137. package/dist/scrape/document.js +2 -2
  138. package/dist/scrape/element.js +7 -1
  139. package/dist/scrape/parser/nodes/html.js +1 -1
  140. package/dist/scrape/spider.d.ts +52 -0
  141. package/dist/scrape/spider.js +620 -38
  142. package/dist/scrape/types.d.ts +2 -0
  143. package/dist/search/google.d.ts +26 -1
  144. package/dist/search/google.js +427 -45
  145. package/dist/search/index.d.ts +1 -1
  146. package/dist/seo/analyzer.d.ts +1 -0
  147. package/dist/seo/analyzer.js +144 -1
  148. package/dist/seo/index.d.ts +1 -1
  149. package/dist/seo/keyword-campaign-analyzer.d.ts +2 -0
  150. package/dist/seo/keyword-campaign-analyzer.js +538 -0
  151. package/dist/seo/keyword-campaign-seed-advanced.d.ts +17 -0
  152. package/dist/seo/keyword-campaign-seed-advanced.js +269 -0
  153. package/dist/seo/keyword-campaign-seed-core.d.ts +29 -0
  154. package/dist/seo/keyword-campaign-seed-core.js +525 -0
  155. package/dist/seo/keyword-campaign-shared.d.ts +165 -0
  156. package/dist/seo/keyword-campaign-shared.js +59 -0
  157. package/dist/seo/keyword-campaign.d.ts +4 -107
  158. package/dist/seo/keyword-campaign.js +2 -380
  159. package/dist/seo/keywords.js +5 -22
  160. package/dist/seo/types.d.ts +19 -0
  161. package/dist/template/index.d.ts +1 -1
  162. package/dist/template/types.d.ts +0 -2
  163. package/dist/testing/index.d.ts +1 -22
  164. package/dist/testing/index.js +1 -11
  165. package/dist/transport/curl.d.ts +5 -1
  166. package/dist/transport/curl.js +207 -50
  167. package/dist/transport/undici.d.ts +4 -3
  168. package/dist/transport/undici.js +123 -49
  169. package/dist/types/index.d.ts +9 -3
  170. package/dist/utils/binary-manager.js +26 -3
  171. package/dist/utils/block-detector.d.ts +8 -0
  172. package/dist/utils/block-detector.js +542 -7
  173. package/dist/version.js +1 -1
  174. package/package.json +12 -1
  175. package/dist/testing/mock-dns-server.d.ts +0 -69
  176. package/dist/testing/mock-dns-server.js +0 -269
  177. package/dist/testing/mock-ftp-server.d.ts +0 -89
  178. package/dist/testing/mock-ftp-server.js +0 -562
  179. package/dist/testing/mock-hls-server.d.ts +0 -80
  180. package/dist/testing/mock-hls-server.js +0 -381
  181. package/dist/testing/mock-http-server.d.ts +0 -124
  182. package/dist/testing/mock-http-server.js +0 -343
  183. package/dist/testing/mock-proxy-server.d.ts +0 -108
  184. package/dist/testing/mock-proxy-server.js +0 -615
  185. package/dist/testing/mock-sse-server.d.ts +0 -76
  186. package/dist/testing/mock-sse-server.js +0 -291
  187. package/dist/testing/mock-telnet-server.d.ts +0 -59
  188. package/dist/testing/mock-telnet-server.js +0 -274
  189. package/dist/testing/mock-udp-server.d.ts +0 -43
  190. package/dist/testing/mock-udp-server.js +0 -188
  191. package/dist/testing/mock-websocket-server.d.ts +0 -76
  192. package/dist/testing/mock-websocket-server.js +0 -334
  193. package/dist/testing/mock-whois-server.d.ts +0 -56
  194. package/dist/testing/mock-whois-server.js +0 -234
  195. package/dist/testing/proxy-certs.d.ts +0 -19
  196. package/dist/testing/proxy-certs.js +0 -208
@@ -1,381 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- const DEFAULT_VARIANTS = [
3
- { name: '360p', bandwidth: 800_000, resolution: '640x360', codecs: 'avc1.4d401e,mp4a.40.2' },
4
- { name: '480p', bandwidth: 1_400_000, resolution: '854x480', codecs: 'avc1.4d401e,mp4a.40.2' },
5
- { name: '720p', bandwidth: 2_800_000, resolution: '1280x720', codecs: 'avc1.4d401f,mp4a.40.2' },
6
- { name: '1080p', bandwidth: 5_000_000, resolution: '1920x1080', codecs: 'avc1.640028,mp4a.40.2' },
7
- ];
8
- export class MockHlsServer extends EventEmitter {
9
- options;
10
- segments = new Map();
11
- currentSequence;
12
- ended = false;
13
- started = false;
14
- realtimeInterval = null;
15
- startTime = 0;
16
- stats = {
17
- playlistRequests: 0,
18
- segmentRequests: 0,
19
- segmentsServed: 0,
20
- bytesServed: 0,
21
- requestLog: [],
22
- };
23
- constructor(options = {}) {
24
- super();
25
- const segmentDuration = options.segmentDuration ?? 6;
26
- this.options = {
27
- mode: 'vod',
28
- segmentDuration,
29
- segmentCount: 10,
30
- windowSize: 3,
31
- startSequence: 0,
32
- realtime: false,
33
- segmentInterval: segmentDuration * 1000,
34
- multiQuality: false,
35
- variants: options.variants ?? DEFAULT_VARIANTS,
36
- encrypted: false,
37
- baseUrl: 'http://mock-hls-server',
38
- delay: 0,
39
- segmentDataGenerator: options.segmentDataGenerator ?? this.defaultSegmentGenerator.bind(this),
40
- ...options,
41
- };
42
- this.currentSequence = this.options.startSequence;
43
- }
44
- get isRunning() {
45
- return this.started && !this.ended;
46
- }
47
- get isEnded() {
48
- return this.ended;
49
- }
50
- get manifestUrl() {
51
- return this.options.multiQuality
52
- ? `${this.options.baseUrl}/master.m3u8`
53
- : `${this.options.baseUrl}/playlist.m3u8`;
54
- }
55
- get segmentCount() {
56
- const variantKey = this.options.multiQuality ? this.options.variants[0].name : 'default';
57
- return this.segments.get(variantKey)?.length ?? 0;
58
- }
59
- get statistics() {
60
- return { ...this.stats };
61
- }
62
- get transport() {
63
- return {
64
- dispatch: async (req) => this.handleRequest(req),
65
- };
66
- }
67
- async start() {
68
- if (this.started) {
69
- throw new Error('Server already started');
70
- }
71
- this.started = true;
72
- this.startTime = Date.now();
73
- if (this.options.mode === 'vod') {
74
- this.initializeVodSegments();
75
- }
76
- else {
77
- this.initializeLiveSegments();
78
- if (this.options.realtime) {
79
- this.startRealtimeSegmentGeneration();
80
- }
81
- }
82
- this.emit('start');
83
- }
84
- async stop() {
85
- if (!this.started)
86
- return;
87
- if (this.realtimeInterval) {
88
- clearInterval(this.realtimeInterval);
89
- this.realtimeInterval = null;
90
- }
91
- this.started = false;
92
- this.emit('stop');
93
- }
94
- endStream() {
95
- if (this.options.mode === 'vod')
96
- return;
97
- this.ended = true;
98
- if (this.realtimeInterval) {
99
- clearInterval(this.realtimeInterval);
100
- this.realtimeInterval = null;
101
- }
102
- this.emit('ended');
103
- }
104
- reset() {
105
- this.segments.clear();
106
- this.currentSequence = this.options.startSequence;
107
- this.ended = false;
108
- this.stats = {
109
- playlistRequests: 0,
110
- segmentRequests: 0,
111
- segmentsServed: 0,
112
- bytesServed: 0,
113
- requestLog: [],
114
- };
115
- if (this.started) {
116
- if (this.options.mode === 'vod') {
117
- this.initializeVodSegments();
118
- }
119
- else {
120
- this.initializeLiveSegments();
121
- }
122
- }
123
- this.emit('reset');
124
- }
125
- addSegment(variant = 'default', options = {}) {
126
- const variantSegments = this.segments.get(variant) ?? [];
127
- const segment = {
128
- sequence: this.currentSequence,
129
- duration: this.options.segmentDuration,
130
- data: options.data ?? this.options.segmentDataGenerator(this.currentSequence, variant),
131
- addedAt: Date.now(),
132
- programDateTime: options.programDateTime,
133
- discontinuity: options.discontinuity,
134
- ...options,
135
- };
136
- variantSegments.push(segment);
137
- this.segments.set(variant, variantSegments);
138
- this.currentSequence++;
139
- if (this.options.mode === 'live' && variantSegments.length > this.options.windowSize) {
140
- variantSegments.shift();
141
- }
142
- this.emit('segment', segment, variant);
143
- return segment;
144
- }
145
- addDiscontinuity(variant = 'default') {
146
- this.addSegment(variant, { discontinuity: true });
147
- }
148
- getSegments(variant = 'default') {
149
- return [...(this.segments.get(variant) ?? [])];
150
- }
151
- async handleRequest(req) {
152
- const url = req.url;
153
- this.stats.requestLog.push({ url, timestamp: Date.now() });
154
- if (this.options.delay > 0) {
155
- await new Promise((resolve) => setTimeout(resolve, this.options.delay));
156
- }
157
- if (url.includes('master.m3u8')) {
158
- return this.handleMasterPlaylist();
159
- }
160
- if (url.includes('.m3u8')) {
161
- return this.handleMediaPlaylist(url);
162
- }
163
- if (url.includes('.ts')) {
164
- return this.handleSegment(url);
165
- }
166
- if (url.includes('.key')) {
167
- return this.handleKey();
168
- }
169
- throw new Error(`Unknown request: ${url}`);
170
- }
171
- handleMasterPlaylist() {
172
- this.stats.playlistRequests++;
173
- const lines = ['#EXTM3U', '#EXT-X-VERSION:3'];
174
- for (const variant of this.options.variants) {
175
- const attrs = [
176
- `BANDWIDTH=${variant.bandwidth}`,
177
- variant.resolution ? `RESOLUTION=${variant.resolution}` : null,
178
- variant.codecs ? `CODECS="${variant.codecs}"` : null,
179
- `NAME="${variant.name}"`,
180
- ]
181
- .filter(Boolean)
182
- .join(',');
183
- lines.push(`#EXT-X-STREAM-INF:${attrs}`);
184
- lines.push(`${variant.name}/playlist.m3u8`);
185
- }
186
- const body = lines.join('\n');
187
- return this.createResponse(body, 'application/vnd.apple.mpegurl');
188
- }
189
- handleMediaPlaylist(url) {
190
- this.stats.playlistRequests++;
191
- let variant = 'default';
192
- if (this.options.multiQuality) {
193
- const match = url.match(/\/(\w+)\/playlist\.m3u8/);
194
- variant = match?.[1] ?? this.options.variants[0].name;
195
- }
196
- if (this.options.mode === 'live' && !this.options.realtime && !this.ended) {
197
- this.addSegmentToAllVariants();
198
- }
199
- const segments = this.segments.get(variant) ?? [];
200
- const lines = [
201
- '#EXTM3U',
202
- '#EXT-X-VERSION:3',
203
- `#EXT-X-TARGETDURATION:${Math.ceil(this.options.segmentDuration)}`,
204
- ];
205
- if (this.options.mode !== 'vod') {
206
- const mediaSequence = segments.length > 0 ? segments[0].sequence : 0;
207
- lines.push(`#EXT-X-MEDIA-SEQUENCE:${mediaSequence}`);
208
- }
209
- if (this.options.mode === 'event') {
210
- lines.push('#EXT-X-PLAYLIST-TYPE:EVENT');
211
- }
212
- else if (this.options.mode === 'vod') {
213
- lines.push('#EXT-X-PLAYLIST-TYPE:VOD');
214
- }
215
- if (this.options.encrypted) {
216
- lines.push(`#EXT-X-KEY:METHOD=AES-128,URI="${this.options.baseUrl}/key.key",IV=0x00000000000000000000000000000001`);
217
- }
218
- for (const segment of segments) {
219
- if (segment.discontinuity) {
220
- lines.push('#EXT-X-DISCONTINUITY');
221
- }
222
- if (segment.programDateTime) {
223
- lines.push(`#EXT-X-PROGRAM-DATE-TIME:${segment.programDateTime.toISOString()}`);
224
- }
225
- lines.push(`#EXTINF:${segment.duration.toFixed(3)},`);
226
- const segmentPath = this.options.multiQuality
227
- ? `${variant}/segment${segment.sequence}.ts`
228
- : `segment${segment.sequence}.ts`;
229
- lines.push(segmentPath);
230
- }
231
- if (this.options.mode === 'vod' || this.ended) {
232
- lines.push('#EXT-X-ENDLIST');
233
- }
234
- const body = lines.join('\n');
235
- return this.createResponse(body, 'application/vnd.apple.mpegurl');
236
- }
237
- handleSegment(url) {
238
- this.stats.segmentRequests++;
239
- const urlPath = url.replace(/^https?:\/\/[^/]+/, '');
240
- const match = urlPath.match(/(?:\/(\w+))?\/segment(\d+)\.ts/);
241
- if (!match) {
242
- return this.createResponse('Not Found', 'text/plain', 404);
243
- }
244
- const variant = match[1] ?? 'default';
245
- const sequence = parseInt(match[2], 10);
246
- const segments = this.segments.get(variant) ?? [];
247
- const segment = segments.find((s) => s.sequence === sequence);
248
- if (!segment) {
249
- return this.createResponse('Not Found', 'text/plain', 404);
250
- }
251
- this.stats.segmentsServed++;
252
- this.stats.bytesServed += segment.data.byteLength;
253
- this.emit('segmentServed', segment, variant);
254
- return this.createResponse(segment.data, 'video/mp2t');
255
- }
256
- handleKey() {
257
- const key = new Uint8Array(16);
258
- for (let i = 0; i < 16; i++) {
259
- key[i] = i;
260
- }
261
- return this.createResponse(key, 'application/octet-stream');
262
- }
263
- createResponse(body, contentType, status = 200) {
264
- const isText = typeof body === 'string';
265
- const blobData = isText ? body : new Uint8Array(body);
266
- return {
267
- ok: status >= 200 && status < 300,
268
- status,
269
- text: async () => (isText ? body : new TextDecoder().decode(body)),
270
- blob: async () => new Blob([blobData]),
271
- arrayBuffer: async () => (isText ? new TextEncoder().encode(body).buffer : body.buffer),
272
- headers: new Headers({
273
- 'content-type': contentType,
274
- 'content-length': String(isText ? body.length : body.byteLength),
275
- }),
276
- };
277
- }
278
- initializeVodSegments() {
279
- const variants = this.options.multiQuality
280
- ? this.options.variants.map((v) => v.name)
281
- : ['default'];
282
- for (const variant of variants) {
283
- this.segments.set(variant, []);
284
- for (let i = 0; i < this.options.segmentCount; i++) {
285
- const segment = {
286
- sequence: this.currentSequence,
287
- duration: this.options.segmentDuration,
288
- data: this.options.segmentDataGenerator(this.currentSequence, variant),
289
- addedAt: Date.now(),
290
- };
291
- this.segments.get(variant).push(segment);
292
- this.currentSequence++;
293
- }
294
- if (this.options.multiQuality) {
295
- this.currentSequence = this.options.startSequence;
296
- }
297
- }
298
- this.currentSequence = this.options.startSequence + this.options.segmentCount;
299
- }
300
- initializeLiveSegments() {
301
- const variants = this.options.multiQuality
302
- ? this.options.variants.map((v) => v.name)
303
- : ['default'];
304
- for (const variant of variants) {
305
- this.segments.set(variant, []);
306
- for (let i = 0; i < this.options.windowSize; i++) {
307
- const segment = {
308
- sequence: this.currentSequence + i,
309
- duration: this.options.segmentDuration,
310
- data: this.options.segmentDataGenerator(this.currentSequence + i, variant),
311
- addedAt: Date.now(),
312
- };
313
- this.segments.get(variant).push(segment);
314
- }
315
- }
316
- this.currentSequence += this.options.windowSize;
317
- }
318
- addSegmentToAllVariants() {
319
- const variants = this.options.multiQuality
320
- ? this.options.variants.map((v) => v.name)
321
- : ['default'];
322
- for (const variant of variants) {
323
- const variantSegments = this.segments.get(variant) ?? [];
324
- const segment = {
325
- sequence: this.currentSequence,
326
- duration: this.options.segmentDuration,
327
- data: this.options.segmentDataGenerator(this.currentSequence, variant),
328
- addedAt: Date.now(),
329
- };
330
- variantSegments.push(segment);
331
- if (this.options.mode === 'live' && variantSegments.length > this.options.windowSize) {
332
- variantSegments.shift();
333
- }
334
- this.segments.set(variant, variantSegments);
335
- this.emit('segment', segment, variant);
336
- }
337
- this.currentSequence++;
338
- }
339
- startRealtimeSegmentGeneration() {
340
- this.realtimeInterval = setInterval(() => {
341
- if (this.ended)
342
- return;
343
- this.addSegmentToAllVariants();
344
- }, this.options.segmentInterval);
345
- }
346
- defaultSegmentGenerator(sequence, _variant) {
347
- const size = 1024 + (sequence % 512);
348
- const data = new Uint8Array(size);
349
- for (let i = 0; i < size; i++) {
350
- data[i] = (sequence * 17 + i * 13) % 256;
351
- }
352
- return data;
353
- }
354
- static async create(options = {}) {
355
- const server = new MockHlsServer(options);
356
- await server.start();
357
- return server;
358
- }
359
- }
360
- export async function createMockHlsVod(segmentCount = 10, options = {}) {
361
- return MockHlsServer.create({
362
- mode: 'vod',
363
- segmentCount,
364
- ...options,
365
- });
366
- }
367
- export async function createMockHlsLive(options = {}) {
368
- return MockHlsServer.create({
369
- mode: 'live',
370
- realtime: true,
371
- segmentDuration: 2,
372
- windowSize: 3,
373
- ...options,
374
- });
375
- }
376
- export async function createMockHlsMultiQuality(options = {}) {
377
- return MockHlsServer.create({
378
- multiQuality: true,
379
- ...options,
380
- });
381
- }
@@ -1,124 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- import { type IncomingMessage } from 'node:http';
3
- export interface MockHttpServerOptions {
4
- port?: number;
5
- host?: string;
6
- defaultResponse?: MockHttpResponse;
7
- delay?: number;
8
- cors?: boolean;
9
- corsOrigin?: string;
10
- }
11
- export interface MockHttpResponse {
12
- status?: number;
13
- body?: any;
14
- headers?: Record<string, string>;
15
- delay?: number;
16
- drop?: boolean;
17
- stream?: {
18
- chunks: (string | Buffer)[];
19
- interval: number;
20
- };
21
- }
22
- export interface MockHttpRequest {
23
- method: string;
24
- path: string;
25
- query: Record<string, string>;
26
- headers: Record<string, string | string[] | undefined>;
27
- body: any;
28
- raw: IncomingMessage;
29
- }
30
- export type MockHttpHandler = (req: MockHttpRequest) => MockHttpResponse | Promise<MockHttpResponse>;
31
- export interface MockHttpStats {
32
- totalRequests: number;
33
- requestsByMethod: Record<string, number>;
34
- requestsByPath: Record<string, number>;
35
- requestLog: Array<{
36
- method: string;
37
- path: string;
38
- status: number;
39
- timestamp: number;
40
- duration: number;
41
- }>;
42
- }
43
- export declare class MockHttpServer extends EventEmitter {
44
- private options;
45
- private httpServer;
46
- private routes;
47
- private _port;
48
- private _started;
49
- private stats;
50
- constructor(options?: MockHttpServerOptions);
51
- get port(): number;
52
- get address(): string;
53
- get url(): string;
54
- get isRunning(): boolean;
55
- get statistics(): MockHttpStats;
56
- get routeCount(): number;
57
- start(): Promise<void>;
58
- stop(): Promise<void>;
59
- reset(): void;
60
- route(method: string, path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
61
- times?: number;
62
- }): this;
63
- get(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
64
- times?: number;
65
- }): this;
66
- post(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
67
- times?: number;
68
- }): this;
69
- put(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
70
- times?: number;
71
- }): this;
72
- patch(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
73
- times?: number;
74
- }): this;
75
- delete(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
76
- times?: number;
77
- }): this;
78
- head(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
79
- times?: number;
80
- }): this;
81
- optionsRoute(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
82
- times?: number;
83
- }): this;
84
- trace(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
85
- times?: number;
86
- }): this;
87
- connect(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
88
- times?: number;
89
- }): this;
90
- purge(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
91
- times?: number;
92
- }): this;
93
- any(path: string, handler: MockHttpResponse | MockHttpHandler, options?: {
94
- times?: number;
95
- }): this;
96
- removeRoute(method: string, path: string): boolean;
97
- clearRoutes(): void;
98
- private handleRequest;
99
- private findRoute;
100
- private sendResponse;
101
- private sendCorsHeaders;
102
- private parseBody;
103
- private pathToRegex;
104
- waitForRequests(count: number, timeout?: number): Promise<void>;
105
- getCallCount(method: string, path: string): number;
106
- static create(options?: MockHttpServerOptions): Promise<MockHttpServer>;
107
- }
108
- export declare function createMockHttpServer(routes?: Record<string, MockHttpResponse>, options?: MockHttpServerOptions): Promise<MockHttpServer>;
109
- export interface WebhookServerOptions extends MockHttpServerOptions {
110
- log?: boolean;
111
- logger?: (webhook: WebhookPayload) => void;
112
- status?: 200 | 204;
113
- }
114
- export interface WebhookPayload {
115
- id: string | null;
116
- timestamp: Date;
117
- method: string;
118
- path: string;
119
- headers: Record<string, string | string[] | undefined>;
120
- body: any;
121
- }
122
- export declare function createWebhookServer(options?: WebhookServerOptions): Promise<MockHttpServer & {
123
- webhooks: WebhookPayload[];
124
- }>;