s3db.js 13.6.0 → 14.0.2

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 (193) hide show
  1. package/README.md +139 -43
  2. package/dist/s3db.cjs +72425 -38970
  3. package/dist/s3db.cjs.map +1 -1
  4. package/dist/s3db.es.js +72177 -38764
  5. package/dist/s3db.es.js.map +1 -1
  6. package/mcp/lib/base-handler.js +157 -0
  7. package/mcp/lib/handlers/connection-handler.js +280 -0
  8. package/mcp/lib/handlers/query-handler.js +533 -0
  9. package/mcp/lib/handlers/resource-handler.js +428 -0
  10. package/mcp/lib/tool-registry.js +336 -0
  11. package/mcp/lib/tools/connection-tools.js +161 -0
  12. package/mcp/lib/tools/query-tools.js +267 -0
  13. package/mcp/lib/tools/resource-tools.js +404 -0
  14. package/package.json +94 -49
  15. package/src/clients/memory-client.class.js +346 -191
  16. package/src/clients/memory-storage.class.js +300 -84
  17. package/src/clients/s3-client.class.js +7 -6
  18. package/src/concerns/geo-encoding.js +19 -2
  19. package/src/concerns/ip.js +59 -9
  20. package/src/concerns/money.js +8 -1
  21. package/src/concerns/password-hashing.js +49 -8
  22. package/src/concerns/plugin-storage.js +186 -18
  23. package/src/concerns/storage-drivers/filesystem-driver.js +284 -0
  24. package/src/database.class.js +139 -29
  25. package/src/errors.js +332 -42
  26. package/src/plugins/api/auth/oidc-auth.js +66 -17
  27. package/src/plugins/api/auth/strategies/base-strategy.class.js +74 -0
  28. package/src/plugins/api/auth/strategies/factory.class.js +63 -0
  29. package/src/plugins/api/auth/strategies/global-strategy.class.js +44 -0
  30. package/src/plugins/api/auth/strategies/path-based-strategy.class.js +83 -0
  31. package/src/plugins/api/auth/strategies/path-rules-strategy.class.js +118 -0
  32. package/src/plugins/api/concerns/failban-manager.js +106 -57
  33. package/src/plugins/api/concerns/opengraph-helper.js +116 -0
  34. package/src/plugins/api/concerns/route-context.js +601 -0
  35. package/src/plugins/api/concerns/state-machine.js +288 -0
  36. package/src/plugins/api/index.js +180 -41
  37. package/src/plugins/api/routes/auth-routes.js +198 -30
  38. package/src/plugins/api/routes/resource-routes.js +19 -4
  39. package/src/plugins/api/server/health-manager.class.js +163 -0
  40. package/src/plugins/api/server/middleware-chain.class.js +310 -0
  41. package/src/plugins/api/server/router.class.js +472 -0
  42. package/src/plugins/api/server.js +280 -1303
  43. package/src/plugins/api/utils/custom-routes.js +17 -5
  44. package/src/plugins/api/utils/guards.js +76 -17
  45. package/src/plugins/api/utils/openapi-generator-cached.class.js +133 -0
  46. package/src/plugins/api/utils/openapi-generator.js +7 -6
  47. package/src/plugins/api/utils/template-engine.js +77 -3
  48. package/src/plugins/audit.plugin.js +30 -8
  49. package/src/plugins/backup.plugin.js +110 -14
  50. package/src/plugins/cache/cache.class.js +22 -5
  51. package/src/plugins/cache/filesystem-cache.class.js +116 -19
  52. package/src/plugins/cache/memory-cache.class.js +211 -57
  53. package/src/plugins/cache/multi-tier-cache.class.js +371 -0
  54. package/src/plugins/cache/partition-aware-filesystem-cache.class.js +168 -47
  55. package/src/plugins/cache/redis-cache.class.js +552 -0
  56. package/src/plugins/cache/s3-cache.class.js +17 -8
  57. package/src/plugins/cache.plugin.js +176 -61
  58. package/src/plugins/cloud-inventory/drivers/alibaba-driver.js +8 -1
  59. package/src/plugins/cloud-inventory/drivers/aws-driver.js +60 -29
  60. package/src/plugins/cloud-inventory/drivers/azure-driver.js +8 -1
  61. package/src/plugins/cloud-inventory/drivers/base-driver.js +16 -2
  62. package/src/plugins/cloud-inventory/drivers/cloudflare-driver.js +8 -1
  63. package/src/plugins/cloud-inventory/drivers/digitalocean-driver.js +8 -1
  64. package/src/plugins/cloud-inventory/drivers/hetzner-driver.js +8 -1
  65. package/src/plugins/cloud-inventory/drivers/linode-driver.js +8 -1
  66. package/src/plugins/cloud-inventory/drivers/mongodb-atlas-driver.js +8 -1
  67. package/src/plugins/cloud-inventory/drivers/vultr-driver.js +8 -1
  68. package/src/plugins/cloud-inventory/index.js +29 -8
  69. package/src/plugins/cloud-inventory/registry.js +64 -42
  70. package/src/plugins/cloud-inventory.plugin.js +240 -138
  71. package/src/plugins/concerns/plugin-dependencies.js +54 -0
  72. package/src/plugins/concerns/resource-names.js +100 -0
  73. package/src/plugins/consumers/index.js +10 -2
  74. package/src/plugins/consumers/sqs-consumer.js +12 -2
  75. package/src/plugins/cookie-farm-suite.plugin.js +278 -0
  76. package/src/plugins/cookie-farm.errors.js +73 -0
  77. package/src/plugins/cookie-farm.plugin.js +869 -0
  78. package/src/plugins/costs.plugin.js +7 -1
  79. package/src/plugins/eventual-consistency/analytics.js +94 -19
  80. package/src/plugins/eventual-consistency/config.js +15 -7
  81. package/src/plugins/eventual-consistency/consolidation.js +29 -11
  82. package/src/plugins/eventual-consistency/garbage-collection.js +3 -1
  83. package/src/plugins/eventual-consistency/helpers.js +39 -14
  84. package/src/plugins/eventual-consistency/install.js +21 -2
  85. package/src/plugins/eventual-consistency/utils.js +32 -10
  86. package/src/plugins/fulltext.plugin.js +38 -11
  87. package/src/plugins/geo.plugin.js +61 -9
  88. package/src/plugins/identity/concerns/config.js +61 -0
  89. package/src/plugins/identity/concerns/mfa-manager.js +15 -2
  90. package/src/plugins/identity/concerns/rate-limit.js +124 -0
  91. package/src/plugins/identity/concerns/resource-schemas.js +9 -1
  92. package/src/plugins/identity/concerns/token-generator.js +29 -4
  93. package/src/plugins/identity/drivers/auth-driver.interface.js +76 -0
  94. package/src/plugins/identity/drivers/client-credentials-driver.js +127 -0
  95. package/src/plugins/identity/drivers/index.js +18 -0
  96. package/src/plugins/identity/drivers/password-driver.js +122 -0
  97. package/src/plugins/identity/email-service.js +17 -2
  98. package/src/plugins/identity/index.js +413 -69
  99. package/src/plugins/identity/oauth2-server.js +413 -30
  100. package/src/plugins/identity/oidc-discovery.js +16 -8
  101. package/src/plugins/identity/rsa-keys.js +115 -35
  102. package/src/plugins/identity/server.js +166 -45
  103. package/src/plugins/identity/session-manager.js +53 -7
  104. package/src/plugins/identity/ui/pages/mfa-verification.js +17 -15
  105. package/src/plugins/identity/ui/routes.js +363 -255
  106. package/src/plugins/importer/index.js +153 -20
  107. package/src/plugins/index.js +9 -2
  108. package/src/plugins/kubernetes-inventory/index.js +6 -0
  109. package/src/plugins/kubernetes-inventory/k8s-driver.js +867 -0
  110. package/src/plugins/kubernetes-inventory/resource-types.js +274 -0
  111. package/src/plugins/kubernetes-inventory.plugin.js +980 -0
  112. package/src/plugins/metrics.plugin.js +64 -16
  113. package/src/plugins/ml/base-model.class.js +25 -15
  114. package/src/plugins/ml/regression-model.class.js +1 -1
  115. package/src/plugins/ml.errors.js +57 -25
  116. package/src/plugins/ml.plugin.js +28 -4
  117. package/src/plugins/namespace.js +210 -0
  118. package/src/plugins/plugin.class.js +180 -8
  119. package/src/plugins/puppeteer/console-monitor.js +729 -0
  120. package/src/plugins/puppeteer/cookie-manager.js +492 -0
  121. package/src/plugins/puppeteer/network-monitor.js +816 -0
  122. package/src/plugins/puppeteer/performance-manager.js +746 -0
  123. package/src/plugins/puppeteer/proxy-manager.js +478 -0
  124. package/src/plugins/puppeteer/stealth-manager.js +556 -0
  125. package/src/plugins/puppeteer.errors.js +81 -0
  126. package/src/plugins/puppeteer.plugin.js +1327 -0
  127. package/src/plugins/queue-consumer.plugin.js +69 -14
  128. package/src/plugins/recon/behaviors/uptime-behavior.js +691 -0
  129. package/src/plugins/recon/concerns/command-runner.js +148 -0
  130. package/src/plugins/recon/concerns/diff-detector.js +372 -0
  131. package/src/plugins/recon/concerns/fingerprint-builder.js +307 -0
  132. package/src/plugins/recon/concerns/process-manager.js +338 -0
  133. package/src/plugins/recon/concerns/report-generator.js +478 -0
  134. package/src/plugins/recon/concerns/security-analyzer.js +571 -0
  135. package/src/plugins/recon/concerns/target-normalizer.js +68 -0
  136. package/src/plugins/recon/config/defaults.js +321 -0
  137. package/src/plugins/recon/config/resources.js +370 -0
  138. package/src/plugins/recon/index.js +778 -0
  139. package/src/plugins/recon/managers/dependency-manager.js +174 -0
  140. package/src/plugins/recon/managers/scheduler-manager.js +179 -0
  141. package/src/plugins/recon/managers/storage-manager.js +745 -0
  142. package/src/plugins/recon/managers/target-manager.js +274 -0
  143. package/src/plugins/recon/stages/asn-stage.js +314 -0
  144. package/src/plugins/recon/stages/certificate-stage.js +84 -0
  145. package/src/plugins/recon/stages/dns-stage.js +107 -0
  146. package/src/plugins/recon/stages/dnsdumpster-stage.js +362 -0
  147. package/src/plugins/recon/stages/fingerprint-stage.js +71 -0
  148. package/src/plugins/recon/stages/google-dorks-stage.js +440 -0
  149. package/src/plugins/recon/stages/http-stage.js +89 -0
  150. package/src/plugins/recon/stages/latency-stage.js +148 -0
  151. package/src/plugins/recon/stages/massdns-stage.js +302 -0
  152. package/src/plugins/recon/stages/osint-stage.js +1373 -0
  153. package/src/plugins/recon/stages/ports-stage.js +169 -0
  154. package/src/plugins/recon/stages/screenshot-stage.js +94 -0
  155. package/src/plugins/recon/stages/secrets-stage.js +514 -0
  156. package/src/plugins/recon/stages/subdomains-stage.js +295 -0
  157. package/src/plugins/recon/stages/tls-audit-stage.js +78 -0
  158. package/src/plugins/recon/stages/vulnerability-stage.js +78 -0
  159. package/src/plugins/recon/stages/web-discovery-stage.js +113 -0
  160. package/src/plugins/recon/stages/whois-stage.js +349 -0
  161. package/src/plugins/recon.plugin.js +75 -0
  162. package/src/plugins/recon.plugin.js.backup +2635 -0
  163. package/src/plugins/relation.errors.js +87 -14
  164. package/src/plugins/replicator.plugin.js +514 -137
  165. package/src/plugins/replicators/base-replicator.class.js +89 -1
  166. package/src/plugins/replicators/bigquery-replicator.class.js +66 -22
  167. package/src/plugins/replicators/dynamodb-replicator.class.js +22 -15
  168. package/src/plugins/replicators/mongodb-replicator.class.js +22 -15
  169. package/src/plugins/replicators/mysql-replicator.class.js +52 -17
  170. package/src/plugins/replicators/planetscale-replicator.class.js +30 -4
  171. package/src/plugins/replicators/postgres-replicator.class.js +62 -27
  172. package/src/plugins/replicators/s3db-replicator.class.js +25 -18
  173. package/src/plugins/replicators/schema-sync.helper.js +3 -3
  174. package/src/plugins/replicators/sqs-replicator.class.js +8 -2
  175. package/src/plugins/replicators/turso-replicator.class.js +23 -3
  176. package/src/plugins/replicators/webhook-replicator.class.js +42 -4
  177. package/src/plugins/s3-queue.plugin.js +464 -65
  178. package/src/plugins/scheduler.plugin.js +20 -6
  179. package/src/plugins/state-machine.plugin.js +40 -9
  180. package/src/plugins/tfstate/README.md +126 -126
  181. package/src/plugins/tfstate/base-driver.js +28 -4
  182. package/src/plugins/tfstate/errors.js +65 -10
  183. package/src/plugins/tfstate/filesystem-driver.js +52 -8
  184. package/src/plugins/tfstate/index.js +163 -90
  185. package/src/plugins/tfstate/s3-driver.js +64 -6
  186. package/src/plugins/ttl.plugin.js +72 -17
  187. package/src/plugins/vector/distances.js +18 -12
  188. package/src/plugins/vector/kmeans.js +26 -4
  189. package/src/resource.class.js +115 -19
  190. package/src/testing/factory.class.js +20 -3
  191. package/src/testing/seeder.class.js +7 -1
  192. package/src/clients/memory-client.md +0 -917
  193. package/src/plugins/cloud-inventory/drivers/mock-drivers.js +0 -449
@@ -0,0 +1,492 @@
1
+ /**
2
+ * CookieManager - Manages cookie farming, rotation, and reputation tracking
3
+ *
4
+ * Strategies:
5
+ * 1. Warmup Sessions - Visit trusted sites to build cookie reputation
6
+ * 2. Reputation Tracking - Monitor success rates and retire bad cookies
7
+ * 3. Age-Based Rotation - Older cookies are more trustworthy
8
+ */
9
+ import { CookieManagerError } from '../puppeteer.errors.js';
10
+
11
+ export class CookieManager {
12
+ constructor(plugin) {
13
+ this.plugin = plugin;
14
+ this.config = plugin.config.cookies;
15
+ this.storage = null;
16
+ this.cookiePool = new Map(); // sessionId -> cookie data
17
+ }
18
+
19
+ /**
20
+ * Initialize cookie manager
21
+ */
22
+ async initialize() {
23
+ this.storage = await this.plugin.database.getResource(this.config.storage.resource);
24
+
25
+ // Load existing cookies into pool if enabled
26
+ if (this.config.farming.enabled) {
27
+ await this._loadCookiePool();
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Load cookie pool from storage
33
+ * @private
34
+ */
35
+ async _loadCookiePool() {
36
+ const limit = this.config.farming.rotation.poolSize;
37
+ const cookies = await this.storage.list({ limit });
38
+
39
+ for (const cookie of cookies) {
40
+ this.cookiePool.set(cookie.sessionId, cookie);
41
+ }
42
+
43
+ this.plugin.emit('cookieManager.poolLoaded', {
44
+ size: this.cookiePool.size
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Load cookies into page
50
+ * @param {Page} page - Puppeteer page
51
+ * @param {string} sessionId - Session identifier
52
+ */
53
+ async loadSession(page, sessionId) {
54
+ // Try to get from pool first
55
+ let session = this.cookiePool.get(sessionId);
56
+
57
+ // If not in pool, try to get from storage
58
+ if (!session) {
59
+ try {
60
+ session = await this.storage.get(sessionId);
61
+ this.cookiePool.set(sessionId, session);
62
+ } catch (err) {
63
+ // Session doesn't exist yet
64
+ return;
65
+ }
66
+ }
67
+
68
+ // Set cookies
69
+ if (session.cookies && session.cookies.length > 0) {
70
+ await page.setCookie(...session.cookies);
71
+ }
72
+
73
+ // Set user agent if available
74
+ if (session.userAgent) {
75
+ await page.setUserAgent(session.userAgent);
76
+ }
77
+
78
+ // Set viewport if available
79
+ if (session.viewport) {
80
+ await page.setViewport(session.viewport);
81
+ }
82
+
83
+ // Update last used timestamp
84
+ session.metadata.lastUsed = Date.now();
85
+ session.metadata.requestCount = (session.metadata.requestCount || 0) + 1;
86
+
87
+ this.plugin.emit('cookieManager.sessionLoaded', {
88
+ sessionId,
89
+ cookieCount: session.cookies.length
90
+ });
91
+ }
92
+
93
+ /**
94
+ * Save cookies from page
95
+ * @param {Page} page - Puppeteer page
96
+ * @param {string} sessionId - Session identifier
97
+ * @param {Object} options - Save options
98
+ */
99
+ async saveSession(page, sessionId, options = {}) {
100
+ const { success = true } = options;
101
+
102
+ // Get cookies from page
103
+ const cookies = await page.cookies();
104
+
105
+ // Get existing session or create new
106
+ let session = this.cookiePool.get(sessionId) || {
107
+ sessionId,
108
+ cookies: [],
109
+ userAgent: page._userAgent,
110
+ viewport: page._viewport,
111
+ proxyId: page._proxyId || null, // IMMUTABLE: Proxy binding
112
+ domain: this._extractMainDomain(cookies),
113
+ date: new Date().toISOString().split('T')[0], // YYYY-MM-DD
114
+ reputation: {
115
+ successCount: 0,
116
+ failCount: 0,
117
+ successRate: 1.0,
118
+ lastUsed: Date.now()
119
+ },
120
+ metadata: {
121
+ createdAt: Date.now(),
122
+ expiresAt: Date.now() + this.config.farming.rotation.maxAge,
123
+ requestCount: 0,
124
+ age: 0
125
+ }
126
+ };
127
+
128
+ // Update cookies
129
+ session.cookies = cookies;
130
+
131
+ // Update domain (in case it changed)
132
+ session.domain = this._extractMainDomain(cookies);
133
+ session.date = new Date().toISOString().split('T')[0];
134
+
135
+ // Update reputation
136
+ if (this.config.farming.reputation.enabled && this.config.farming.reputation.trackSuccess) {
137
+ if (success) {
138
+ session.reputation.successCount++;
139
+ } else {
140
+ session.reputation.failCount++;
141
+ }
142
+
143
+ const total = session.reputation.successCount + session.reputation.failCount;
144
+ session.reputation.successRate = session.reputation.successCount / total;
145
+ }
146
+
147
+ // Update age
148
+ session.metadata.age = Date.now() - session.metadata.createdAt;
149
+
150
+ // Save to storage if auto-save enabled
151
+ if (this.config.storage.autoSave) {
152
+ try {
153
+ const existing = await this.storage.get(sessionId);
154
+ await this.storage.update(sessionId, session);
155
+ } catch (err) {
156
+ await this.storage.insert(session);
157
+ }
158
+ }
159
+
160
+ // Update pool
161
+ this.cookiePool.set(sessionId, session);
162
+
163
+ this.plugin.emit('cookieManager.sessionSaved', {
164
+ sessionId,
165
+ cookieCount: cookies.length,
166
+ reputation: session.reputation
167
+ });
168
+ }
169
+
170
+ /**
171
+ * Farm cookies for a session
172
+ * @param {string} sessionId - Session identifier
173
+ * @returns {Promise<void>}
174
+ */
175
+ async farmCookies(sessionId) {
176
+ if (!this.config.farming.enabled || !this.config.farming.warmup.enabled) {
177
+ throw new CookieManagerError('Cookie farming is not enabled', {
178
+ operation: 'farmCookies',
179
+ retriable: false,
180
+ suggestion: 'Enable config.farming.enabled and config.farming.warmup.enabled to farm cookies.'
181
+ });
182
+ }
183
+
184
+ const warmupConfig = this.config.farming.warmup;
185
+ const pages = [...warmupConfig.pages];
186
+
187
+ // Randomize order if enabled
188
+ if (warmupConfig.randomOrder) {
189
+ pages.sort(() => Math.random() - 0.5);
190
+ }
191
+
192
+ this.plugin.emit('cookieManager.farmingStarted', {
193
+ sessionId,
194
+ pages: pages.length
195
+ });
196
+
197
+ // Visit each warmup page
198
+ for (const url of pages) {
199
+ try {
200
+ const page = await this.plugin.navigate(url, { useSession: sessionId });
201
+
202
+ // Wait random time on page
203
+ const timeOnPage = warmupConfig.timePerPage.min +
204
+ Math.random() * (warmupConfig.timePerPage.max - warmupConfig.timePerPage.min);
205
+
206
+ // Perform interactions if enabled
207
+ if (warmupConfig.interactions.scroll) {
208
+ await this._randomScroll(page);
209
+ }
210
+
211
+ if (warmupConfig.interactions.hover) {
212
+ await this._randomHover(page);
213
+ }
214
+
215
+ if (warmupConfig.interactions.click) {
216
+ await this._randomClick(page);
217
+ }
218
+
219
+ // Wait remaining time
220
+ await this._delay(timeOnPage);
221
+
222
+ // Save cookies with success=true
223
+ await this.saveSession(page, sessionId, { success: true });
224
+
225
+ // Close page
226
+ await page.close();
227
+
228
+ this.plugin.emit('cookieManager.warmupPageCompleted', {
229
+ sessionId,
230
+ url
231
+ });
232
+ } catch (err) {
233
+ this.plugin.emit('cookieManager.warmupPageFailed', {
234
+ sessionId,
235
+ url,
236
+ error: err.message
237
+ });
238
+ }
239
+ }
240
+
241
+ this.plugin.emit('cookieManager.farmingCompleted', { sessionId });
242
+ }
243
+
244
+ /**
245
+ * Get best cookie from pool based on reputation
246
+ * @param {Object} options - Selection options
247
+ * @returns {Promise<Object>}
248
+ */
249
+ async getBestCookie(options = {}) {
250
+ if (!this.config.farming.enabled || !this.config.farming.reputation.enabled) {
251
+ throw new CookieManagerError('Cookie farming reputation must be enabled to select best cookies', {
252
+ operation: 'getBestCookie',
253
+ retriable: false,
254
+ suggestion: 'Enable config.farming.reputation.enabled before calling getBestCookie().'
255
+ });
256
+ }
257
+
258
+ const candidates = Array.from(this.cookiePool.values())
259
+ .filter(session => {
260
+ // Filter out retired cookies
261
+ if (session.reputation.successRate < this.config.farming.reputation.retireThreshold) {
262
+ return false;
263
+ }
264
+
265
+ // Filter out expired cookies
266
+ if (Date.now() > session.metadata.expiresAt) {
267
+ return false;
268
+ }
269
+
270
+ // Filter out overused cookies
271
+ if (session.metadata.requestCount >= this.config.farming.rotation.requestsPerCookie) {
272
+ return false;
273
+ }
274
+
275
+ return true;
276
+ });
277
+
278
+ if (candidates.length === 0) {
279
+ return null;
280
+ }
281
+
282
+ // Score cookies based on reputation and age
283
+ const scored = candidates.map(session => {
284
+ let score = session.reputation.successRate;
285
+
286
+ // Age boost - older cookies are more trustworthy
287
+ if (this.config.farming.reputation.ageBoost) {
288
+ const ageInHours = session.metadata.age / (1000 * 60 * 60);
289
+ const ageBoost = Math.min(ageInHours / 24, 1) * 0.2; // Up to 20% boost
290
+ score += ageBoost;
291
+ }
292
+
293
+ return { session, score };
294
+ });
295
+
296
+ // Sort by score descending
297
+ scored.sort((a, b) => b.score - a.score);
298
+
299
+ return scored[0].session;
300
+ }
301
+
302
+ /**
303
+ * Rotate cookies - remove expired/overused cookies
304
+ * @returns {Promise<number>}
305
+ */
306
+ async rotateCookies() {
307
+ if (!this.config.farming.enabled || !this.config.farming.rotation.enabled) {
308
+ return 0;
309
+ }
310
+
311
+ let removed = 0;
312
+ const now = Date.now();
313
+
314
+ for (const [sessionId, session] of this.cookiePool.entries()) {
315
+ let shouldRemove = false;
316
+
317
+ // Check expiration
318
+ if (now > session.metadata.expiresAt) {
319
+ shouldRemove = true;
320
+ }
321
+
322
+ // Check request count
323
+ if (session.metadata.requestCount >= this.config.farming.rotation.requestsPerCookie) {
324
+ shouldRemove = true;
325
+ }
326
+
327
+ // Check reputation
328
+ if (this.config.farming.reputation.enabled &&
329
+ session.reputation.successRate < this.config.farming.reputation.retireThreshold) {
330
+ shouldRemove = true;
331
+ }
332
+
333
+ if (shouldRemove) {
334
+ this.cookiePool.delete(sessionId);
335
+
336
+ // Remove from storage
337
+ try {
338
+ await this.storage.remove(sessionId);
339
+ } catch (err) {
340
+ // Ignore errors
341
+ }
342
+
343
+ removed++;
344
+ }
345
+ }
346
+
347
+ if (removed > 0) {
348
+ this.plugin.emit('cookieManager.cookiesRotated', { removed });
349
+ }
350
+
351
+ return removed;
352
+ }
353
+
354
+ /**
355
+ * Get cookie pool statistics
356
+ * @returns {Promise<Object>}
357
+ */
358
+ async getStats() {
359
+ const sessions = Array.from(this.cookiePool.values());
360
+
361
+ const stats = {
362
+ total: sessions.length,
363
+ healthy: 0,
364
+ expired: 0,
365
+ overused: 0,
366
+ lowReputation: 0,
367
+ averageAge: 0,
368
+ averageSuccessRate: 0,
369
+ averageRequestCount: 0
370
+ };
371
+
372
+ if (sessions.length === 0) {
373
+ return stats;
374
+ }
375
+
376
+ const now = Date.now();
377
+ let totalAge = 0;
378
+ let totalSuccessRate = 0;
379
+ let totalRequestCount = 0;
380
+
381
+ for (const session of sessions) {
382
+ // Count expired
383
+ if (now > session.metadata.expiresAt) {
384
+ stats.expired++;
385
+ continue;
386
+ }
387
+
388
+ // Count overused
389
+ if (session.metadata.requestCount >= this.config.farming.rotation.requestsPerCookie) {
390
+ stats.overused++;
391
+ continue;
392
+ }
393
+
394
+ // Count low reputation
395
+ if (session.reputation.successRate < this.config.farming.reputation.retireThreshold) {
396
+ stats.lowReputation++;
397
+ continue;
398
+ }
399
+
400
+ // Count healthy
401
+ stats.healthy++;
402
+
403
+ // Accumulate metrics
404
+ totalAge += session.metadata.age;
405
+ totalSuccessRate += session.reputation.successRate;
406
+ totalRequestCount += session.metadata.requestCount;
407
+ }
408
+
409
+ // Calculate averages
410
+ stats.averageAge = totalAge / stats.healthy || 0;
411
+ stats.averageSuccessRate = totalSuccessRate / stats.healthy || 0;
412
+ stats.averageRequestCount = totalRequestCount / stats.healthy || 0;
413
+
414
+ return stats;
415
+ }
416
+
417
+ /**
418
+ * Random scroll helper
419
+ * @private
420
+ */
421
+ async _randomScroll(page) {
422
+ const scrollDistance = Math.floor(Math.random() * 500) + 200;
423
+ await page.evaluate((distance) => {
424
+ window.scrollBy(0, distance);
425
+ }, scrollDistance);
426
+ }
427
+
428
+ /**
429
+ * Random hover helper
430
+ * @private
431
+ */
432
+ async _randomHover(page) {
433
+ try {
434
+ const elements = await page.$$('a, button');
435
+ if (elements.length > 0) {
436
+ const randomElement = elements[Math.floor(Math.random() * elements.length)];
437
+ await randomElement.hover();
438
+ }
439
+ } catch (err) {
440
+ // Ignore errors
441
+ }
442
+ }
443
+
444
+ /**
445
+ * Random click helper
446
+ * @private
447
+ */
448
+ async _randomClick(page) {
449
+ try {
450
+ // Find clickable elements that won't navigate away
451
+ const elements = await page.$$('button:not([type="submit"]), div[role="button"]');
452
+ if (elements.length > 0) {
453
+ const randomElement = elements[Math.floor(Math.random() * elements.length)];
454
+ await randomElement.click();
455
+ }
456
+ } catch (err) {
457
+ // Ignore errors
458
+ }
459
+ }
460
+
461
+ /**
462
+ * Extract main domain from cookies
463
+ * @private
464
+ */
465
+ _extractMainDomain(cookies) {
466
+ if (!cookies || cookies.length === 0) {
467
+ return 'unknown';
468
+ }
469
+
470
+ // Get most common domain from cookies
471
+ const domains = {};
472
+ cookies.forEach(cookie => {
473
+ const domain = cookie.domain || 'unknown';
474
+ domains[domain] = (domains[domain] || 0) + 1;
475
+ });
476
+
477
+ // Return domain with most cookies
478
+ return Object.entries(domains)
479
+ .sort((a, b) => b[1] - a[1])[0][0]
480
+ .replace(/^\./, ''); // Remove leading dot
481
+ }
482
+
483
+ /**
484
+ * Delay helper
485
+ * @private
486
+ */
487
+ async _delay(ms) {
488
+ return new Promise(resolve => setTimeout(resolve, ms));
489
+ }
490
+ }
491
+
492
+ export default CookieManager;