@taodigital/crawler 1.2.0 → 1.2.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.
- package/dist/ai-login.js.map +1 -1
- package/dist/crawler.js.map +2 -2
- package/dist/extractors/summary-extractor.js.map +2 -2
- package/dist/failure-analysis-agent.js.map +1 -1
- package/dist/http-engine.js.map +2 -2
- package/dist/interactive-probe.js.map +1 -1
- package/dist/job-queue.js +60 -18
- package/dist/job-queue.js.map +2 -2
- package/dist/native-crawler.js.map +1 -1
- package/dist/sitemap.js +1 -1
- package/dist/sitemap.js.map +2 -2
- package/dist/test-executor.js.map +2 -2
- package/dist/visual-diff-verdict.js.map +1 -1
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/src/http-engine.ts +12 -7
- package/src/job-queue.ts +104 -32
- package/src/sitemap.ts +1 -1
- package/types/job-queue.d.ts +5 -1
package/dist/job-queue.js
CHANGED
|
@@ -460,25 +460,34 @@ async function getJob(tenantId, jobId) {
|
|
|
460
460
|
(tx) => tx.platformJob.findFirst({ where: { id: jobId, tenantId } })
|
|
461
461
|
);
|
|
462
462
|
}
|
|
463
|
-
async function
|
|
464
|
-
return withTenant(tenantId,
|
|
465
|
-
|
|
463
|
+
async function countJobs(tenantId, projectId) {
|
|
464
|
+
return withTenant(tenantId, (tx) => tx.platformJob.count({ where: { tenantId, projectId } }));
|
|
465
|
+
}
|
|
466
|
+
async function listJobs(tenantId, projectId, { skip = 0, take = 50 } = {}) {
|
|
467
|
+
const jobs = await withTenant(
|
|
468
|
+
tenantId,
|
|
469
|
+
(tx) => tx.platformJob.findMany({
|
|
466
470
|
where: { tenantId, projectId },
|
|
467
471
|
orderBy: { queuedAt: "desc" },
|
|
468
|
-
|
|
469
|
-
|
|
472
|
+
skip,
|
|
473
|
+
take
|
|
474
|
+
})
|
|
475
|
+
);
|
|
476
|
+
if (jobs.length === 0) return jobs;
|
|
477
|
+
let modelByJobId = /* @__PURE__ */ new Map();
|
|
478
|
+
try {
|
|
470
479
|
const jobIds = jobs.map((j) => j.id);
|
|
471
|
-
|
|
472
|
-
const modelRows = await tx.lLMCallLog.groupBy({
|
|
480
|
+
const modelRows = await prismaAdmin.lLMCallLog.groupBy({
|
|
473
481
|
by: ["jobId"],
|
|
474
482
|
where: { tenantId, jobId: { in: jobIds } },
|
|
475
483
|
_max: { model: true, calledAt: true }
|
|
476
484
|
});
|
|
477
|
-
|
|
485
|
+
modelByJobId = new Map(
|
|
478
486
|
modelRows.filter((r) => r.jobId && r._max?.model).map((r) => [r.jobId, r._max.model])
|
|
479
487
|
);
|
|
480
|
-
|
|
481
|
-
}
|
|
488
|
+
} catch {
|
|
489
|
+
}
|
|
490
|
+
return jobs.map((j) => ({ ...j, llmModel: modelByJobId.get(j.id) ?? null }));
|
|
482
491
|
}
|
|
483
492
|
async function cancelJob(tenantId, jobId) {
|
|
484
493
|
const controller = runningControllers.get(jobId);
|
|
@@ -2355,6 +2364,15 @@ async function processMultiRoleCrawlJob(jobId, config) {
|
|
|
2355
2364
|
);
|
|
2356
2365
|
const savedCrawlConfig = proj?.crawlConfig ?? {};
|
|
2357
2366
|
const credentialProfiles = config.credentialProfiles ?? [];
|
|
2367
|
+
const multiRoleWsProxy = await AppBrain.getTenantProxyConfig(tenantId).catch(() => null);
|
|
2368
|
+
const multiRoleResolvedProxyUrl = (() => {
|
|
2369
|
+
const projectProxy = savedCrawlConfig?.proxyUrl;
|
|
2370
|
+
if (projectProxy === "agent" || multiRoleWsProxy?.mode === "agent") return "agent";
|
|
2371
|
+
if (projectProxy === "auto" || multiRoleWsProxy?.mode === "auto") return "auto";
|
|
2372
|
+
if (projectProxy && projectProxy !== "auto" && projectProxy !== "agent") return projectProxy;
|
|
2373
|
+
if (multiRoleWsProxy?.mode === "custom" && multiRoleWsProxy.proxyUrl) return multiRoleWsProxy.proxyUrl;
|
|
2374
|
+
return void 0;
|
|
2375
|
+
})();
|
|
2358
2376
|
await updateJobProgress(tenantId, jobId, 10, "Enqueuing primary crawl\u2026");
|
|
2359
2377
|
const primaryJobId = await enqueueJob("CRAWL", {
|
|
2360
2378
|
tenantId,
|
|
@@ -2366,7 +2384,7 @@ async function processMultiRoleCrawlJob(jobId, config) {
|
|
|
2366
2384
|
startUrls: savedCrawlConfig.seedUrls?.length ? savedCrawlConfig.seedUrls : void 0,
|
|
2367
2385
|
deviceProfiles: savedCrawlConfig.deviceProfiles ?? ["DESKTOP"],
|
|
2368
2386
|
loginInstructions: savedCrawlConfig.loginInstructions,
|
|
2369
|
-
proxyUrl:
|
|
2387
|
+
proxyUrl: multiRoleResolvedProxyUrl,
|
|
2370
2388
|
useSitemap: true,
|
|
2371
2389
|
sitemapUrl: savedCrawlConfig.sitemapUrl
|
|
2372
2390
|
});
|
|
@@ -2415,7 +2433,7 @@ async function processMultiRoleCrawlJob(jobId, config) {
|
|
|
2415
2433
|
storageState: savedCrawlConfig.storageState,
|
|
2416
2434
|
deviceProfiles: savedCrawlConfig.deviceProfiles ?? ["DESKTOP"],
|
|
2417
2435
|
loginInstructions: savedCrawlConfig.loginInstructions,
|
|
2418
|
-
proxyUrl:
|
|
2436
|
+
proxyUrl: multiRoleResolvedProxyUrl
|
|
2419
2437
|
});
|
|
2420
2438
|
roleJobs.push({ roleName: profile.name, jobId: roleJobId });
|
|
2421
2439
|
logger.info({ roleJobId, roleName: profile.name, projectId }, "[multi-role-crawl] ROLE_CRAWL enqueued");
|
|
@@ -2494,6 +2512,15 @@ async function processRoleCrawlJob(jobId, config) {
|
|
|
2494
2512
|
(tx) => tx.project.findUnique({ where: { id: projectId }, select: { crawlConfig: true } })
|
|
2495
2513
|
);
|
|
2496
2514
|
const savedCrawlConfig = proj?.crawlConfig ?? {};
|
|
2515
|
+
const roleCrawlWsProxy = await AppBrain.getTenantProxyConfig(tenantId).catch(() => null);
|
|
2516
|
+
const roleCrawlResolvedProxyUrl = (() => {
|
|
2517
|
+
const projectProxy = config.proxyUrl ?? savedCrawlConfig?.proxyUrl;
|
|
2518
|
+
if (projectProxy === "agent" || roleCrawlWsProxy?.mode === "agent") return "agent";
|
|
2519
|
+
if (projectProxy === "auto" || roleCrawlWsProxy?.mode === "auto") return "auto";
|
|
2520
|
+
if (projectProxy && projectProxy !== "auto" && projectProxy !== "agent") return projectProxy;
|
|
2521
|
+
if (roleCrawlWsProxy?.mode === "custom" && roleCrawlWsProxy.proxyUrl) return roleCrawlWsProxy.proxyUrl;
|
|
2522
|
+
return void 0;
|
|
2523
|
+
})();
|
|
2497
2524
|
const runtimeCreds = config.credentials ? {
|
|
2498
2525
|
...config.credentials,
|
|
2499
2526
|
...config.credentials.totpSecret ? { getOneTimeCode: async () => generateTOTP(config.credentials.totpSecret) } : {}
|
|
@@ -2503,7 +2530,7 @@ async function processRoleCrawlJob(jobId, config) {
|
|
|
2503
2530
|
...config,
|
|
2504
2531
|
credentials: runtimeCreds,
|
|
2505
2532
|
storageState: config.storageState ?? savedCrawlConfig.storageState,
|
|
2506
|
-
proxyUrl:
|
|
2533
|
+
proxyUrl: roleCrawlResolvedProxyUrl,
|
|
2507
2534
|
loginInstructions: config.loginInstructions ?? savedCrawlConfig.loginInstructions,
|
|
2508
2535
|
abortSignal: controller.signal,
|
|
2509
2536
|
jobId,
|
|
@@ -3024,14 +3051,20 @@ async function processRepoScanJob(jobId, config) {
|
|
|
3024
3051
|
const isJavaTestFile = (p) => p.endsWith(".java") && (/[A-Z]\w*Tests?\.java$/.test(p) || /\/tests?\//.test(p) && /[A-Z][a-z]/.test(p.split("/").pop() ?? ""));
|
|
3025
3052
|
const testGlobs = minimatch ? Array.from(/* @__PURE__ */ new Set([
|
|
3026
3053
|
testGlob,
|
|
3027
|
-
|
|
3028
|
-
...testGlob
|
|
3054
|
+
// TS variants: add all common suffixes whenever the primary glob is any *.spec.ts or *.test.ts
|
|
3055
|
+
...testGlob.endsWith(".spec.ts") ? ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.tsx", "**/*.cy.ts", "**/*.e2e.ts", "**/*.integration.ts", "**/*.smoke.ts", "**/*.steps.ts"] : [],
|
|
3056
|
+
...testGlob.endsWith(".test.ts") ? ["**/*.spec.ts", "**/*.test.tsx", "**/*.spec.tsx", "**/*.cy.ts", "**/*.e2e.ts", "**/*.integration.ts", "**/*.smoke.ts", "**/*.steps.ts"] : [],
|
|
3057
|
+
// JS variants
|
|
3058
|
+
...testGlob.endsWith(".spec.js") ? ["**/*.test.js", "**/*.cy.js", "**/*.e2e.js", "**/*.integration.js", "**/*.smoke.js", "**/*.steps.js"] : [],
|
|
3059
|
+
...testGlob.endsWith(".test.js") ? ["**/*.spec.js", "**/*.cy.js", "**/*.e2e.js", "**/*.integration.js", "**/*.smoke.js", "**/*.steps.js"] : [],
|
|
3060
|
+
// Gherkin feature files are always relevant regardless of primary glob
|
|
3061
|
+
...framework === "cucumber" || framework === "gherkin" ? ["**/*.feature"] : []
|
|
3029
3062
|
])) : [];
|
|
3030
3063
|
const testPaths = treeResult.paths.filter((p) => {
|
|
3031
3064
|
if (language === "java") return isJavaTestFile(p);
|
|
3032
3065
|
if (language === "python") return isPythonTestFile(p);
|
|
3033
3066
|
if (testGlobs.length) return testGlobs.some((g) => minimatch(p, g, { matchBase: true }));
|
|
3034
|
-
return p.endsWith(".spec.ts") || p.endsWith(".spec.js") || p.endsWith(".test.ts") || p.endsWith(".test.js") || p.endsWith(".cy.ts") || p.endsWith(".cy.js") || p.endsWith("_test.py") || p.includes("/test_");
|
|
3067
|
+
return p.endsWith(".spec.ts") || p.endsWith(".spec.js") || p.endsWith(".test.ts") || p.endsWith(".test.js") || p.endsWith(".cy.ts") || p.endsWith(".cy.js") || p.endsWith(".e2e.ts") || p.endsWith(".e2e.js") || p.endsWith(".integration.ts") || p.endsWith(".integration.js") || p.endsWith(".smoke.ts") || p.endsWith(".steps.ts") || p.endsWith(".feature") || p.endsWith("_test.py") || p.includes("/test_");
|
|
3035
3068
|
}).slice(0, 2e3);
|
|
3036
3069
|
await updateJobProgress(tenantId, jobId, 40, `Found ${testPaths.length} test files`);
|
|
3037
3070
|
if (testPaths.length === 0) {
|
|
@@ -3299,8 +3332,16 @@ async function processRepoScanJob(jobId, config) {
|
|
|
3299
3332
|
try {
|
|
3300
3333
|
const mainSourcePaths = language === "java" ? treeResult.paths.filter((p) => /^src\/main\/java\//.test(p)).slice(0, 50) : [];
|
|
3301
3334
|
const testPathSet = new Set(testPaths);
|
|
3302
|
-
const
|
|
3303
|
-
const
|
|
3335
|
+
const isFrameworkSupportFile = (p) => /\.(page|fixture|helper|util|utils|data|actions|assertions|locator|locators|steps)\.(ts|js|tsx|jsx)$/.test(p);
|
|
3336
|
+
const isGenericSourceFile = (p) => (p.endsWith(".ts") || p.endsWith(".js") || p.endsWith(".tsx") || p.endsWith(".jsx")) && !p.endsWith(".d.ts") && !p.includes("node_modules/") && !p.includes("dist/") && !p.includes(".next/");
|
|
3337
|
+
const candidateSourcePaths = treeResult.paths.filter(
|
|
3338
|
+
(p) => isGenericSourceFile(p) && !testPathSet.has(p)
|
|
3339
|
+
);
|
|
3340
|
+
const supportFilePaths = candidateSourcePaths.filter(isFrameworkSupportFile).slice(0, 80);
|
|
3341
|
+
const supportPathSet = new Set(supportFilePaths);
|
|
3342
|
+
const otherSourcePaths = candidateSourcePaths.filter((p) => !supportPathSet.has(p)).slice(0, 60);
|
|
3343
|
+
const sourceFilePaths = language === "typescript" || language === "javascript" ? [...supportFilePaths, ...otherSourcePaths] : [];
|
|
3344
|
+
const allPathsForProfile = [...testPaths, ...mainSourcePaths, ...sourceFilePaths].slice(0, 400);
|
|
3304
3345
|
const freshProfile = await extractStyleProfile(styleSampleFiles, framework, language, tenantId, projectId, jobId, allPathsForProfile, treeResult.paths);
|
|
3305
3346
|
if (freshProfile) styleProfile = freshProfile;
|
|
3306
3347
|
} catch {
|
|
@@ -3787,6 +3828,7 @@ export {
|
|
|
3787
3828
|
claimNextQueuedJob,
|
|
3788
3829
|
claimSpecificJob,
|
|
3789
3830
|
classifyFailure,
|
|
3831
|
+
countJobs,
|
|
3790
3832
|
createTrackedJob,
|
|
3791
3833
|
dispatchClaimedJob,
|
|
3792
3834
|
enqueueJob,
|