s3db.js 18.0.11-next.1534f717 → 18.0.11-next.e8e71b5b

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 (190) hide show
  1. package/dist/clients/recker-http-handler.js +56 -8
  2. package/dist/clients/recker-http-handler.js.map +1 -1
  3. package/dist/concerns/high-performance-inserter.js +6 -34
  4. package/dist/concerns/high-performance-inserter.js.map +1 -1
  5. package/dist/concerns/id/alphabets.js +150 -0
  6. package/dist/concerns/id/alphabets.js.map +1 -0
  7. package/dist/concerns/id/entropy.js +243 -0
  8. package/dist/concerns/id/entropy.js.map +1 -0
  9. package/dist/concerns/id/generators/nanoid.js +74 -0
  10. package/dist/concerns/id/generators/nanoid.js.map +1 -0
  11. package/dist/concerns/id/generators/sid.js +73 -0
  12. package/dist/concerns/id/generators/sid.js.map +1 -0
  13. package/dist/concerns/id/generators/ulid.js +208 -0
  14. package/dist/concerns/id/generators/ulid.js.map +1 -0
  15. package/dist/concerns/id/generators/uuid-v7.js +150 -0
  16. package/dist/concerns/id/generators/uuid-v7.js.map +1 -0
  17. package/dist/concerns/id/index.js +74 -0
  18. package/dist/concerns/id/index.js.map +1 -0
  19. package/dist/concerns/plugin-storage.js +114 -0
  20. package/dist/concerns/plugin-storage.js.map +1 -1
  21. package/dist/concerns/s3-errors.js +72 -0
  22. package/dist/concerns/s3-errors.js.map +1 -0
  23. package/dist/concerns/s3-key.js +54 -0
  24. package/dist/concerns/s3-key.js.map +1 -0
  25. package/dist/concerns/safe-merge.js +47 -0
  26. package/dist/concerns/safe-merge.js.map +1 -0
  27. package/dist/core/resource-config-validator.js +12 -2
  28. package/dist/core/resource-config-validator.js.map +1 -1
  29. package/dist/core/resource-partitions.class.js +12 -1
  30. package/dist/core/resource-partitions.class.js.map +1 -1
  31. package/dist/core/resource-persistence.class.js +41 -12
  32. package/dist/core/resource-persistence.class.js.map +1 -1
  33. package/dist/core/resource-query.class.js +21 -47
  34. package/dist/core/resource-query.class.js.map +1 -1
  35. package/dist/database/database-connection.class.js +3 -6
  36. package/dist/database/database-connection.class.js.map +1 -1
  37. package/dist/database/database-plugins.class.js +7 -13
  38. package/dist/database/database-plugins.class.js.map +1 -1
  39. package/dist/plugins/concerns/s3-mutex.class.js +155 -0
  40. package/dist/plugins/concerns/s3-mutex.class.js.map +1 -0
  41. package/dist/plugins/eventual-consistency/consolidation.js +4 -7
  42. package/dist/plugins/eventual-consistency/consolidation.js.map +1 -1
  43. package/dist/plugins/eventual-consistency/garbage-collection.js +3 -6
  44. package/dist/plugins/eventual-consistency/garbage-collection.js.map +1 -1
  45. package/dist/plugins/queue-consumer.plugin.js +10 -16
  46. package/dist/plugins/queue-consumer.plugin.js.map +1 -1
  47. package/dist/plugins/recon/managers/scheduler-manager.js +3 -5
  48. package/dist/plugins/recon/managers/scheduler-manager.js.map +1 -1
  49. package/dist/plugins/recon/stages/recker-asn-stage.js +279 -0
  50. package/dist/plugins/recon/stages/recker-asn-stage.js.map +1 -0
  51. package/dist/plugins/recon/stages/recker-dns-stage.js +227 -0
  52. package/dist/plugins/recon/stages/recker-dns-stage.js.map +1 -0
  53. package/dist/plugins/recon/stages/recker-scrape-stage.js +369 -0
  54. package/dist/plugins/recon/stages/recker-scrape-stage.js.map +1 -0
  55. package/dist/plugins/replicator.plugin.js +13 -31
  56. package/dist/plugins/replicator.plugin.js.map +1 -1
  57. package/dist/plugins/replicators/base-replicator.class.js +10 -23
  58. package/dist/plugins/replicators/base-replicator.class.js.map +1 -1
  59. package/dist/plugins/spider/recker-link-discoverer.js +544 -0
  60. package/dist/plugins/spider/recker-link-discoverer.js.map +1 -0
  61. package/dist/plugins/spider/recker-llms-validator.js +334 -0
  62. package/dist/plugins/spider/recker-llms-validator.js.map +1 -0
  63. package/dist/plugins/spider/recker-robots-validator.js +336 -0
  64. package/dist/plugins/spider/recker-robots-validator.js.map +1 -0
  65. package/dist/plugins/spider/recker-security-adapter.js +325 -0
  66. package/dist/plugins/spider/recker-security-adapter.js.map +1 -0
  67. package/dist/plugins/spider/recker-seo-adapter.js +399 -0
  68. package/dist/plugins/spider/recker-seo-adapter.js.map +1 -0
  69. package/dist/plugins/spider/recker-sitemap-validator.js +406 -0
  70. package/dist/plugins/spider/recker-sitemap-validator.js.map +1 -0
  71. package/dist/resource.class.js +2 -0
  72. package/dist/resource.class.js.map +1 -1
  73. package/dist/s3db.cjs +444 -219
  74. package/dist/s3db.cjs.map +1 -1
  75. package/dist/s3db.es.js +445 -220
  76. package/dist/s3db.es.js.map +1 -1
  77. package/dist/stream/resource-reader.class.js +5 -7
  78. package/dist/stream/resource-reader.class.js.map +1 -1
  79. package/dist/stream/resource-writer.class.js +5 -7
  80. package/dist/stream/resource-writer.class.js.map +1 -1
  81. package/dist/tasks/tasks-pool.class.js +31 -0
  82. package/dist/tasks/tasks-pool.class.js.map +1 -1
  83. package/dist/types/clients/recker-http-handler.d.ts +1 -0
  84. package/dist/types/clients/recker-http-handler.d.ts.map +1 -1
  85. package/dist/types/clients/types.d.ts +14 -0
  86. package/dist/types/clients/types.d.ts.map +1 -1
  87. package/dist/types/concerns/high-performance-inserter.d.ts.map +1 -1
  88. package/dist/types/concerns/id/alphabets.d.ts +125 -0
  89. package/dist/types/concerns/id/alphabets.d.ts.map +1 -0
  90. package/dist/types/concerns/id/entropy.d.ts +84 -0
  91. package/dist/types/concerns/id/entropy.d.ts.map +1 -0
  92. package/dist/types/concerns/id/generators/nanoid.d.ts +46 -0
  93. package/dist/types/concerns/id/generators/nanoid.d.ts.map +1 -0
  94. package/dist/types/concerns/id/generators/sid.d.ts +45 -0
  95. package/dist/types/concerns/id/generators/sid.d.ts.map +1 -0
  96. package/dist/types/concerns/id/generators/ulid.d.ts +71 -0
  97. package/dist/types/concerns/id/generators/ulid.d.ts.map +1 -0
  98. package/dist/types/concerns/id/generators/uuid-v7.d.ts +60 -0
  99. package/dist/types/concerns/id/generators/uuid-v7.d.ts.map +1 -0
  100. package/dist/types/concerns/id/index.d.ts +51 -0
  101. package/dist/types/concerns/id/index.d.ts.map +1 -0
  102. package/dist/types/concerns/plugin-storage.d.ts +25 -0
  103. package/dist/types/concerns/plugin-storage.d.ts.map +1 -1
  104. package/dist/types/concerns/s3-errors.d.ts +20 -0
  105. package/dist/types/concerns/s3-errors.d.ts.map +1 -0
  106. package/dist/types/concerns/s3-key.d.ts +30 -0
  107. package/dist/types/concerns/s3-key.d.ts.map +1 -0
  108. package/dist/types/concerns/safe-merge.d.ts +22 -0
  109. package/dist/types/concerns/safe-merge.d.ts.map +1 -0
  110. package/dist/types/core/resource-config-validator.d.ts.map +1 -1
  111. package/dist/types/core/resource-partitions.class.d.ts.map +1 -1
  112. package/dist/types/core/resource-persistence.class.d.ts.map +1 -1
  113. package/dist/types/core/resource-query.class.d.ts.map +1 -1
  114. package/dist/types/database/database-connection.class.d.ts.map +1 -1
  115. package/dist/types/database/database-plugins.class.d.ts.map +1 -1
  116. package/dist/types/plugins/concerns/s3-mutex.class.d.ts +30 -0
  117. package/dist/types/plugins/concerns/s3-mutex.class.d.ts.map +1 -0
  118. package/dist/types/plugins/eventual-consistency/consolidation.d.ts.map +1 -1
  119. package/dist/types/plugins/eventual-consistency/garbage-collection.d.ts.map +1 -1
  120. package/dist/types/plugins/queue-consumer.plugin.d.ts.map +1 -1
  121. package/dist/types/plugins/recon/managers/scheduler-manager.d.ts.map +1 -1
  122. package/dist/types/plugins/recon/stages/recker-asn-stage.d.ts +90 -0
  123. package/dist/types/plugins/recon/stages/recker-asn-stage.d.ts.map +1 -0
  124. package/dist/types/plugins/recon/stages/recker-dns-stage.d.ts +125 -0
  125. package/dist/types/plugins/recon/stages/recker-dns-stage.d.ts.map +1 -0
  126. package/dist/types/plugins/recon/stages/recker-scrape-stage.d.ts +96 -0
  127. package/dist/types/plugins/recon/stages/recker-scrape-stage.d.ts.map +1 -0
  128. package/dist/types/plugins/replicator.plugin.d.ts.map +1 -1
  129. package/dist/types/plugins/replicators/base-replicator.class.d.ts.map +1 -1
  130. package/dist/types/plugins/spider/recker-link-discoverer.d.ts +54 -0
  131. package/dist/types/plugins/spider/recker-link-discoverer.d.ts.map +1 -0
  132. package/dist/types/plugins/spider/recker-llms-validator.d.ts +105 -0
  133. package/dist/types/plugins/spider/recker-llms-validator.d.ts.map +1 -0
  134. package/dist/types/plugins/spider/recker-robots-validator.d.ts +92 -0
  135. package/dist/types/plugins/spider/recker-robots-validator.d.ts.map +1 -0
  136. package/dist/types/plugins/spider/recker-security-adapter.d.ts +83 -0
  137. package/dist/types/plugins/spider/recker-security-adapter.d.ts.map +1 -0
  138. package/dist/types/plugins/spider/recker-seo-adapter.d.ts +187 -0
  139. package/dist/types/plugins/spider/recker-seo-adapter.d.ts.map +1 -0
  140. package/dist/types/plugins/spider/recker-sitemap-validator.d.ts +121 -0
  141. package/dist/types/plugins/spider/recker-sitemap-validator.d.ts.map +1 -0
  142. package/dist/types/resource.class.d.ts.map +1 -1
  143. package/dist/types/stream/resource-reader.class.d.ts.map +1 -1
  144. package/dist/types/stream/resource-writer.class.d.ts.map +1 -1
  145. package/dist/types/tasks/tasks-pool.class.d.ts +23 -0
  146. package/dist/types/tasks/tasks-pool.class.d.ts.map +1 -1
  147. package/mcp/prompts/index.ts +275 -0
  148. package/mcp/resources/index.ts +322 -0
  149. package/mcp/tools/plugins.ts +1137 -0
  150. package/mcp/tools/streams.ts +340 -0
  151. package/package.json +20 -22
  152. package/src/clients/recker-http-handler.ts +74 -8
  153. package/src/clients/types.ts +14 -0
  154. package/src/concerns/high-performance-inserter.ts +18 -57
  155. package/src/concerns/id/alphabets.ts +175 -0
  156. package/src/concerns/id/entropy.ts +286 -0
  157. package/src/concerns/id/generators/sid.ts +90 -0
  158. package/src/concerns/id/generators/ulid.ts +249 -0
  159. package/src/concerns/id/generators/uuid-v7.ts +179 -0
  160. package/src/concerns/id/index.ts +167 -0
  161. package/src/concerns/plugin-storage.ts +144 -0
  162. package/src/concerns/s3-errors.ts +97 -0
  163. package/src/concerns/s3-key.ts +62 -0
  164. package/src/concerns/safe-merge.ts +60 -0
  165. package/src/core/resource-config-validator.ts +9 -2
  166. package/src/core/resource-partitions.class.ts +14 -1
  167. package/src/core/resource-persistence.class.ts +47 -13
  168. package/src/core/resource-query.class.ts +21 -46
  169. package/src/database/database-connection.class.ts +7 -6
  170. package/src/database/database-plugins.class.ts +15 -13
  171. package/src/plugins/concerns/s3-mutex.class.ts +228 -0
  172. package/src/plugins/eventual-consistency/consolidation.ts +8 -7
  173. package/src/plugins/eventual-consistency/garbage-collection.ts +7 -6
  174. package/src/plugins/queue-consumer.plugin.ts +21 -19
  175. package/src/plugins/recon/managers/scheduler-manager.ts +7 -5
  176. package/src/plugins/recon/stages/recker-asn-stage.ts +385 -0
  177. package/src/plugins/recon/stages/recker-dns-stage.ts +360 -0
  178. package/src/plugins/recon/stages/recker-scrape-stage.ts +509 -0
  179. package/src/plugins/replicator.plugin.ts +41 -35
  180. package/src/plugins/replicators/base-replicator.class.ts +17 -23
  181. package/src/plugins/spider/recker-link-discoverer.ts +645 -0
  182. package/src/plugins/spider/recker-llms-validator.ts +500 -0
  183. package/src/plugins/spider/recker-robots-validator.ts +473 -0
  184. package/src/plugins/spider/recker-security-adapter.ts +489 -0
  185. package/src/plugins/spider/recker-seo-adapter.ts +605 -0
  186. package/src/plugins/spider/recker-sitemap-validator.ts +621 -0
  187. package/src/resource.class.ts +2 -0
  188. package/src/stream/resource-reader.class.ts +10 -8
  189. package/src/stream/resource-writer.class.ts +10 -8
  190. package/src/tasks/tasks-pool.class.ts +46 -0
@@ -0,0 +1,360 @@
1
+ /**
2
+ * ReckerDNSStage
3
+ *
4
+ * DNS Intelligence using Recker's DNS toolkit
5
+ *
6
+ * Discovers:
7
+ * - DNS records (A, AAAA, MX, TXT, NS)
8
+ * - Security records (SPF, DMARC, DKIM, CAA)
9
+ * - DNS health score
10
+ *
11
+ * Uses Recker's native DNS resolution (no external dependencies like dig)
12
+ * Falls back to DNSDumpsterStage if Recker is not available
13
+ */
14
+
15
+ import type { CommandRunner } from '../concerns/command-runner.js';
16
+
17
+ export interface ReconPlugin {
18
+ commandRunner: CommandRunner;
19
+ config: {
20
+ curl?: {
21
+ userAgent?: string;
22
+ };
23
+ storage?: {
24
+ persistRawOutput?: boolean;
25
+ };
26
+ };
27
+ }
28
+
29
+ export interface Target {
30
+ host: string;
31
+ protocol?: string;
32
+ port?: number;
33
+ path?: string;
34
+ }
35
+
36
+ export interface ReckerDNSFeatureConfig {
37
+ timeout?: number;
38
+ includeSecurityRecords?: boolean;
39
+ includeHealthCheck?: boolean;
40
+ }
41
+
42
+ export interface ARecord {
43
+ hostname: string;
44
+ ip: string;
45
+ }
46
+
47
+ export interface MXRecord {
48
+ priority: string;
49
+ hostname: string;
50
+ ip: string;
51
+ }
52
+
53
+ export interface TXTRecord {
54
+ content: string;
55
+ }
56
+
57
+ export interface NSRecord {
58
+ hostname: string;
59
+ ip: string | null;
60
+ }
61
+
62
+ export interface DNSRecords {
63
+ A: ARecord[];
64
+ AAAA: ARecord[];
65
+ MX: MXRecord[];
66
+ TXT: TXTRecord[];
67
+ NS: NSRecord[];
68
+ }
69
+
70
+ export interface SecurityRecords {
71
+ spf: string[];
72
+ dmarc: string | null;
73
+ dkim: { found: boolean; record?: string } | null;
74
+ caa: { issue?: string[]; issuewild?: string[] } | null;
75
+ }
76
+
77
+ export interface HealthCheck {
78
+ score: number;
79
+ grade: string;
80
+ checks: Array<{
81
+ name: string;
82
+ status: 'pass' | 'warn' | 'fail';
83
+ message: string;
84
+ }>;
85
+ }
86
+
87
+ export interface ReckerDNSAggregatedResult {
88
+ status: string;
89
+ host: string;
90
+ dnsRecords: DNSRecords;
91
+ securityRecords: SecurityRecords | null;
92
+ healthCheck: HealthCheck | null;
93
+ errors: Record<string, string>;
94
+ }
95
+
96
+ export interface ReckerDNSResult extends ReckerDNSAggregatedResult {
97
+ _individual: {
98
+ recker: { status: string; source: string };
99
+ fallback: { status: string; source: string } | null;
100
+ };
101
+ _aggregated: ReckerDNSAggregatedResult;
102
+ }
103
+
104
+ type ReckerDNSClient = {
105
+ resolve4(hostname: string): Promise<string[]>;
106
+ resolve6(hostname: string): Promise<string[]>;
107
+ resolveMx(hostname: string): Promise<Array<{ priority: number; exchange: string }>>;
108
+ resolveTxt(hostname: string): Promise<string[]>;
109
+ resolveNs(hostname: string): Promise<string[]>;
110
+ getSecurityRecords(domain: string): Promise<{
111
+ spf?: string[];
112
+ dmarc?: string;
113
+ dkim?: string;
114
+ caa?: { issue?: string[]; issuewild?: string[] };
115
+ }>;
116
+ };
117
+
118
+ type ReckerCheckDnsHealth = (domain: string) => Promise<{
119
+ score: number;
120
+ grade: string;
121
+ checks: Array<{ name: string; status: 'pass' | 'warn' | 'fail'; message: string }>;
122
+ }>;
123
+
124
+ type ReckerCheckDkim = (domain: string, selector?: string) => Promise<{
125
+ found: boolean;
126
+ record?: string;
127
+ }>;
128
+
129
+ export class ReckerDNSStage {
130
+ private plugin: ReconPlugin;
131
+ private config: ReconPlugin['config'];
132
+
133
+ private reckerAvailable: boolean | null = null;
134
+ private dnsClient: ReckerDNSClient | null = null;
135
+ private checkDnsHealth: ReckerCheckDnsHealth | null = null;
136
+ private checkDkim: ReckerCheckDkim | null = null;
137
+ private fallbackStage: import('./dnsdumpster-stage.js').DNSDumpsterStage | null = null;
138
+
139
+ constructor(plugin: ReconPlugin) {
140
+ this.plugin = plugin;
141
+ this.config = plugin.config;
142
+ }
143
+
144
+ private async _checkReckerAvailability(): Promise<boolean> {
145
+ if (this.reckerAvailable !== null) {
146
+ return this.reckerAvailable;
147
+ }
148
+
149
+ try {
150
+ const dnsModule = await import('recker/dns');
151
+ const toolkitModule = await import('recker/dns-toolkit');
152
+
153
+ this.dnsClient = dnsModule.createDNS() as unknown as ReckerDNSClient;
154
+ this.checkDnsHealth = toolkitModule.checkDnsHealth as ReckerCheckDnsHealth;
155
+ this.checkDkim = toolkitModule.checkDkim as ReckerCheckDkim;
156
+
157
+ this.reckerAvailable = true;
158
+ return true;
159
+ } catch {
160
+ this.reckerAvailable = false;
161
+ return false;
162
+ }
163
+ }
164
+
165
+ private async _getFallbackStage(): Promise<import('./dnsdumpster-stage.js').DNSDumpsterStage> {
166
+ if (!this.fallbackStage) {
167
+ const { DNSDumpsterStage } = await import('./dnsdumpster-stage.js');
168
+ this.fallbackStage = new DNSDumpsterStage(this.plugin);
169
+ }
170
+ return this.fallbackStage;
171
+ }
172
+
173
+ async execute(target: Target, options: ReckerDNSFeatureConfig = {}): Promise<ReckerDNSResult> {
174
+ const isReckerAvailable = await this._checkReckerAvailability();
175
+
176
+ if (!isReckerAvailable) {
177
+ return this._executeFallback(target, options);
178
+ }
179
+
180
+ const result: ReckerDNSAggregatedResult = {
181
+ status: 'ok',
182
+ host: target.host,
183
+ dnsRecords: {
184
+ A: [],
185
+ AAAA: [],
186
+ MX: [],
187
+ TXT: [],
188
+ NS: []
189
+ },
190
+ securityRecords: null,
191
+ healthCheck: null,
192
+ errors: {}
193
+ };
194
+
195
+ try {
196
+ const [aRecords, aaaaRecords, mxRecords, txtRecords, nsRecords] = await Promise.all([
197
+ this._resolveA(target.host),
198
+ this._resolveAAAA(target.host),
199
+ this._resolveMX(target.host),
200
+ this._resolveTXT(target.host),
201
+ this._resolveNS(target.host)
202
+ ]);
203
+
204
+ result.dnsRecords.A = aRecords;
205
+ result.dnsRecords.AAAA = aaaaRecords;
206
+ result.dnsRecords.MX = mxRecords;
207
+ result.dnsRecords.TXT = txtRecords;
208
+ result.dnsRecords.NS = nsRecords;
209
+
210
+ if (options.includeSecurityRecords !== false) {
211
+ result.securityRecords = await this._getSecurityRecords(target.host);
212
+ }
213
+
214
+ if (options.includeHealthCheck) {
215
+ result.healthCheck = await this._getHealthCheck(target.host);
216
+ }
217
+
218
+ } catch (error: any) {
219
+ result.status = 'error';
220
+ result.errors.general = error.message;
221
+ }
222
+
223
+ return {
224
+ _individual: {
225
+ recker: { status: 'ok', source: 'recker/dns' },
226
+ fallback: null
227
+ },
228
+ _aggregated: result,
229
+ ...result
230
+ };
231
+ }
232
+
233
+ private async _resolveA(host: string): Promise<ARecord[]> {
234
+ try {
235
+ const ips = await this.dnsClient!.resolve4(host);
236
+ return ips.map(ip => ({ hostname: host, ip }));
237
+ } catch {
238
+ return [];
239
+ }
240
+ }
241
+
242
+ private async _resolveAAAA(host: string): Promise<ARecord[]> {
243
+ try {
244
+ const ips = await this.dnsClient!.resolve6(host);
245
+ return ips.map(ip => ({ hostname: host, ip }));
246
+ } catch {
247
+ return [];
248
+ }
249
+ }
250
+
251
+ private async _resolveMX(host: string): Promise<MXRecord[]> {
252
+ try {
253
+ const records = await this.dnsClient!.resolveMx(host);
254
+ return records.map(r => ({
255
+ priority: String(r.priority),
256
+ hostname: r.exchange,
257
+ ip: ''
258
+ }));
259
+ } catch {
260
+ return [];
261
+ }
262
+ }
263
+
264
+ private async _resolveTXT(host: string): Promise<TXTRecord[]> {
265
+ try {
266
+ const records = await this.dnsClient!.resolveTxt(host);
267
+ return records.map(content => ({ content }));
268
+ } catch {
269
+ return [];
270
+ }
271
+ }
272
+
273
+ private async _resolveNS(host: string): Promise<NSRecord[]> {
274
+ try {
275
+ const records = await this.dnsClient!.resolveNs(host);
276
+ return records.map(hostname => ({ hostname, ip: null }));
277
+ } catch {
278
+ return [];
279
+ }
280
+ }
281
+
282
+ private async _getSecurityRecords(host: string): Promise<SecurityRecords> {
283
+ try {
284
+ const security = await this.dnsClient!.getSecurityRecords(host);
285
+
286
+ let dkim: { found: boolean; record?: string } | null = null;
287
+ if (this.checkDkim) {
288
+ try {
289
+ dkim = await this.checkDkim(host, 'default');
290
+ } catch {
291
+ dkim = { found: false };
292
+ }
293
+ }
294
+
295
+ return {
296
+ spf: security.spf || [],
297
+ dmarc: security.dmarc || null,
298
+ dkim,
299
+ caa: security.caa || null
300
+ };
301
+ } catch {
302
+ return {
303
+ spf: [],
304
+ dmarc: null,
305
+ dkim: null,
306
+ caa: null
307
+ };
308
+ }
309
+ }
310
+
311
+ private async _getHealthCheck(host: string): Promise<HealthCheck | null> {
312
+ if (!this.checkDnsHealth) return null;
313
+
314
+ try {
315
+ const health = await this.checkDnsHealth(host);
316
+ return {
317
+ score: health.score,
318
+ grade: health.grade,
319
+ checks: health.checks
320
+ };
321
+ } catch {
322
+ return null;
323
+ }
324
+ }
325
+
326
+ private async _executeFallback(target: Target, options: ReckerDNSFeatureConfig): Promise<ReckerDNSResult> {
327
+ const fallback = await this._getFallbackStage();
328
+ const fallbackResult = await fallback.execute(target, {
329
+ timeout: options.timeout,
330
+ fallbackToDig: true
331
+ });
332
+
333
+ return {
334
+ _individual: {
335
+ recker: { status: 'unavailable', source: 'recker not installed' },
336
+ fallback: { status: 'ok', source: 'dnsdumpster' }
337
+ },
338
+ _aggregated: {
339
+ status: fallbackResult.status,
340
+ host: fallbackResult.host,
341
+ dnsRecords: fallbackResult.dnsRecords,
342
+ securityRecords: null,
343
+ healthCheck: null,
344
+ errors: fallbackResult.errors
345
+ },
346
+ status: fallbackResult.status,
347
+ host: fallbackResult.host,
348
+ dnsRecords: fallbackResult.dnsRecords,
349
+ securityRecords: null,
350
+ healthCheck: null,
351
+ errors: fallbackResult.errors
352
+ };
353
+ }
354
+
355
+ isReckerEnabled(): boolean {
356
+ return this.reckerAvailable === true;
357
+ }
358
+ }
359
+
360
+ export default ReckerDNSStage;