mcp-scraper 0.77.0 → 0.78.0
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/CHANGELOG.md +16 -0
- package/README.md +1 -1
- package/dist/{analytics-repository-AUTJK4HK.js → analytics-repository-D5LEGQG3.js} +3 -3
- package/dist/bin/api-server.js +4 -4
- package/dist/bin/mcp-scraper-cli.js +3 -3
- package/dist/bin/mcp-scraper-core.js +7 -7
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.js +7 -7
- package/dist/bin/paa-harvest.js +4 -4
- package/dist/{chunk-DTJ56S5B.js → chunk-2P2ZVRPK.js} +189 -57
- package/dist/{chunk-E6Y3VCOJ.js → chunk-3PUMNEOC.js} +3 -3
- package/dist/{chunk-KIPIBPUB.js → chunk-47ZCUBM5.js} +1 -1
- package/dist/{chunk-IBQNOZ7E.js → chunk-74CCAY6T.js} +1 -1
- package/dist/{chunk-7RQULQF3.js → chunk-B6L73AO4.js} +1 -1
- package/dist/{chunk-WFQ2E4WE.js → chunk-BTQ23KCT.js} +1 -1
- package/dist/{chunk-IP7UDXMU.js → chunk-FODYEDZK.js} +3 -3
- package/dist/{chunk-PJEEKOUM.js → chunk-FUMG43EN.js} +1 -1
- package/dist/{chunk-GT6MP4SU.js → chunk-IYYRSVRQ.js} +1 -1
- package/dist/{chunk-A66DGFOU.js → chunk-KAGHJQFO.js} +1 -1
- package/dist/{chunk-CXY5WV45.js → chunk-NGLZ6UJR.js} +1 -1
- package/dist/{chunk-WEFPBAAG.js → chunk-OU4FV2RP.js} +140 -4
- package/dist/{chunk-F5TK4KMT.js → chunk-OUBH6XMY.js} +1 -1
- package/dist/{chunk-77LQV73B.js → chunk-OWF2JJKN.js} +13 -1
- package/dist/{chunk-F6MUGMRN.js → chunk-UFJJGXVO.js} +702 -165
- package/dist/{chunk-KBTUPRTF.js → chunk-VEQPA65D.js} +1 -1
- package/dist/{chunk-D2O7V2CT.js → chunk-VMWSXKUQ.js} +1 -1
- package/dist/{chunk-7HF3T7P2.js → chunk-ZUCU2A6V.js} +1 -1
- package/dist/{db-566MOHHD.js → db-TA567JLA.js} +17 -1
- package/dist/{extract-bundle-OO74L67T.js → extract-bundle-P2DTUVY3.js} +3 -3
- package/dist/{gmail-service-TIU4V5JA.js → gmail-service-HN57R2GS.js} +4 -4
- package/dist/index.cjs +714 -165
- package/dist/index.d.cts +83 -1
- package/dist/index.d.ts +83 -1
- package/dist/index.js +4 -4
- package/dist/{lead-list-enrichment-repository-WWEMJ7EN.js → lead-list-enrichment-repository-5LEWW4X7.js} +2 -2
- package/dist/{location-data-repository-H4B2BWGY.js → location-data-repository-AHKDXTEQ.js} +2 -2
- package/dist/{server-EKRNKKLU.js → server-6B2OG3NN.js} +312 -89
- package/dist/{site-extract-repository-B47JB62U.js → site-extract-repository-XKSVXSSY.js} +2 -2
- package/dist/{worker-DR6R7J46.js → worker-2BYACLNF.js} +6 -6
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
queuedCommonsDocumentCount,
|
|
11
11
|
semanticCommonsEntityScores,
|
|
12
12
|
typeFromMime
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-BTQ23KCT.js";
|
|
14
14
|
import {
|
|
15
15
|
SITE_EXTRACT_ARTIFACT_PREFIX,
|
|
16
16
|
abandonExtractSettlement,
|
|
@@ -41,13 +41,13 @@ import {
|
|
|
41
41
|
setExtractJobTotal,
|
|
42
42
|
settleExtractJob,
|
|
43
43
|
terminalExtractJobStatus
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-VMWSXKUQ.js";
|
|
45
45
|
import {
|
|
46
46
|
REQUIRED_LOCATION_STATE_CODES,
|
|
47
47
|
importHostedCensusPlacesCsv,
|
|
48
48
|
importHostedZipGroupsCsv,
|
|
49
49
|
listActiveHostedLocationDatasets
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-OUBH6XMY.js";
|
|
51
51
|
import {
|
|
52
52
|
cancelPendingLeadListEnrichmentRows,
|
|
53
53
|
claimLeadListEnrichmentOutbox,
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
saveLeadListEnrichmentRowResult,
|
|
75
75
|
setInitializingLeadListEnrichmentConcurrencyLock,
|
|
76
76
|
stableCanonicalJson
|
|
77
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-KAGHJQFO.js";
|
|
78
78
|
import {
|
|
79
79
|
ConnectedUsageBillingError,
|
|
80
80
|
ConnectedUsagePreflightInputSchema,
|
|
@@ -101,7 +101,7 @@ import {
|
|
|
101
101
|
probeNangoConnectionDirect,
|
|
102
102
|
recordNangoConnectionCost,
|
|
103
103
|
settleConnectedUsage
|
|
104
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-3PUMNEOC.js";
|
|
105
105
|
import {
|
|
106
106
|
ANALYTICS_CONTENT_SORTS,
|
|
107
107
|
AnalyticsIdentityProfileError,
|
|
@@ -185,7 +185,7 @@ import {
|
|
|
185
185
|
upsertAnalyticsAdSpend,
|
|
186
186
|
upsertAnalyticsHostGroup,
|
|
187
187
|
verifyAnalyticsWebhookSignature
|
|
188
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-74CCAY6T.js";
|
|
189
189
|
import {
|
|
190
190
|
claimServiceConnectionAction,
|
|
191
191
|
ensureServiceConnectionsSchema,
|
|
@@ -198,7 +198,7 @@ import {
|
|
|
198
198
|
setServiceConnectionUserLabel,
|
|
199
199
|
signSession,
|
|
200
200
|
verifySession
|
|
201
|
-
} from "./chunk-
|
|
201
|
+
} from "./chunk-FUMG43EN.js";
|
|
202
202
|
import {
|
|
203
203
|
classifyHarvestProblem,
|
|
204
204
|
createHarvestAttemptRecorder,
|
|
@@ -207,7 +207,7 @@ import {
|
|
|
207
207
|
harvestProblemResponse,
|
|
208
208
|
publicErrorBoundary,
|
|
209
209
|
serializeHarvestProblem
|
|
210
|
-
} from "./chunk-
|
|
210
|
+
} from "./chunk-47ZCUBM5.js";
|
|
211
211
|
import "./chunk-OZJMVCDK.js";
|
|
212
212
|
import {
|
|
213
213
|
BACKUP_LAST_RESORT_ATTEMPTS,
|
|
@@ -216,18 +216,20 @@ import {
|
|
|
216
216
|
backupProxyAvailable,
|
|
217
217
|
brightDataSerpEnabled,
|
|
218
218
|
buildYouTubeChannelVideosUrl,
|
|
219
|
+
classifyGoogleOutboundLink,
|
|
219
220
|
cleanupBackupProxyId,
|
|
220
221
|
createBackupProxyIdSafe,
|
|
221
222
|
deleteKernelProxyId,
|
|
222
223
|
detectPageUserAgent,
|
|
223
224
|
detectRuntimeUserAgent,
|
|
224
225
|
harvest,
|
|
226
|
+
questionIdFor,
|
|
225
227
|
resolveBackupKernelProxyId,
|
|
226
228
|
resolveKernelProxyId,
|
|
227
229
|
serpArrivalUrl,
|
|
228
230
|
validateProviderSessionId,
|
|
229
231
|
withRuntimeUserAgent
|
|
230
|
-
} from "./chunk-
|
|
232
|
+
} from "./chunk-UFJJGXVO.js";
|
|
231
233
|
import {
|
|
232
234
|
AnalyticsConfirmedPersonProjectionSchema,
|
|
233
235
|
AnalyticsCrmFieldSchema,
|
|
@@ -314,7 +316,7 @@ import {
|
|
|
314
316
|
resolveDeploymentProfile,
|
|
315
317
|
resolveLocalSourcebookSchemaType,
|
|
316
318
|
transcribeMediaUrl
|
|
317
|
-
} from "./chunk-
|
|
319
|
+
} from "./chunk-2P2ZVRPK.js";
|
|
318
320
|
import {
|
|
319
321
|
auditImageUrls,
|
|
320
322
|
auditImages,
|
|
@@ -338,7 +340,7 @@ import {
|
|
|
338
340
|
sanitizeAttempts,
|
|
339
341
|
sanitizeHarvestResult,
|
|
340
342
|
sanitizeOutboundDiagnostics
|
|
341
|
-
} from "./chunk-
|
|
343
|
+
} from "./chunk-B6L73AO4.js";
|
|
342
344
|
import {
|
|
343
345
|
BROWSER_OPEN_MIN_BALANCE_MC,
|
|
344
346
|
CONCURRENCY_PACK_INVOICE_DESCRIPTION,
|
|
@@ -397,7 +399,7 @@ import {
|
|
|
397
399
|
recordKernelSession,
|
|
398
400
|
recordVendorUsage,
|
|
399
401
|
runWithCostContext
|
|
400
|
-
} from "./chunk-
|
|
402
|
+
} from "./chunk-NGLZ6UJR.js";
|
|
401
403
|
import {
|
|
402
404
|
listWorkflowDefinitions,
|
|
403
405
|
runWorkflow,
|
|
@@ -407,7 +409,7 @@ import {
|
|
|
407
409
|
workflowOutputBaseDir,
|
|
408
410
|
workflowStepCount,
|
|
409
411
|
workflowSupportsSteps
|
|
410
|
-
} from "./chunk-
|
|
412
|
+
} from "./chunk-VEQPA65D.js";
|
|
411
413
|
import {
|
|
412
414
|
csvRecords,
|
|
413
415
|
parseCsv,
|
|
@@ -422,7 +424,7 @@ import {
|
|
|
422
424
|
RawMapsHoursRowSchema,
|
|
423
425
|
RawMapsOverviewSchema,
|
|
424
426
|
RawMapsReviewStatsSchema
|
|
425
|
-
} from "./chunk-
|
|
427
|
+
} from "./chunk-OWF2JJKN.js";
|
|
426
428
|
import {
|
|
427
429
|
extractContactEvidence
|
|
428
430
|
} from "./chunk-VXLU74YZ.js";
|
|
@@ -433,7 +435,7 @@ import {
|
|
|
433
435
|
} from "./chunk-GGZEC22A.js";
|
|
434
436
|
import {
|
|
435
437
|
PACKAGE_VERSION
|
|
436
|
-
} from "./chunk-
|
|
438
|
+
} from "./chunk-ZUCU2A6V.js";
|
|
437
439
|
import {
|
|
438
440
|
CaptchaError,
|
|
439
441
|
MapsSearchIncompletePageError,
|
|
@@ -444,11 +446,12 @@ import {
|
|
|
444
446
|
buildPublicErrorEnvelope,
|
|
445
447
|
cancelJob,
|
|
446
448
|
checkRateLimit,
|
|
447
|
-
|
|
449
|
+
checkpointDurablePaaJob,
|
|
448
450
|
claimDurablePaaJob,
|
|
449
451
|
claimStripeEvent,
|
|
452
|
+
completeDurablePaaJob,
|
|
453
|
+
completeExpiredDurablePaaJob,
|
|
450
454
|
completeJob,
|
|
451
|
-
completeRunningJob,
|
|
452
455
|
completeStripeEvent,
|
|
453
456
|
completeWorkflowRunRecord,
|
|
454
457
|
consumeCode,
|
|
@@ -468,8 +471,9 @@ import {
|
|
|
468
471
|
debitMcIdempotent,
|
|
469
472
|
deleteWorkflowSchedule,
|
|
470
473
|
expireOldLots,
|
|
474
|
+
failDurablePaaJob,
|
|
475
|
+
failExpiredDurablePaaJob,
|
|
471
476
|
failJob,
|
|
472
|
-
failRunningJob,
|
|
473
477
|
failStripeEvent,
|
|
474
478
|
failWorkflowRunRecord,
|
|
475
479
|
getBillingLedgerSummary,
|
|
@@ -503,8 +507,8 @@ import {
|
|
|
503
507
|
listInboxMessages,
|
|
504
508
|
listJobs,
|
|
505
509
|
listRecentTerminalDurablePaaJobs,
|
|
510
|
+
listRecoverableDurablePaaJobs,
|
|
506
511
|
listRequestEvents,
|
|
507
|
-
listStaleRunningDurablePaaJobs,
|
|
508
512
|
listUsers,
|
|
509
513
|
listUsersDueForConnectedAccountBillingReconciliation,
|
|
510
514
|
listWorkflowArtifacts,
|
|
@@ -521,7 +525,9 @@ import {
|
|
|
521
525
|
reconcileBalanceMc,
|
|
522
526
|
recordWorkflowWebhookDelivery,
|
|
523
527
|
registerClient,
|
|
528
|
+
renewDurablePaaLease,
|
|
524
529
|
replaceWorkflowArtifacts,
|
|
530
|
+
requeueExpiredDurablePaaJob,
|
|
525
531
|
resolveUserByMemorySubscription,
|
|
526
532
|
revokeApiKey,
|
|
527
533
|
rotateApiKey,
|
|
@@ -540,7 +546,7 @@ import {
|
|
|
540
546
|
updateHarvestAttemptProviderTelemetry,
|
|
541
547
|
upsertPageSnapshot,
|
|
542
548
|
verifyPassword
|
|
543
|
-
} from "./chunk-
|
|
549
|
+
} from "./chunk-OU4FV2RP.js";
|
|
544
550
|
|
|
545
551
|
// src/blog/registry.ts
|
|
546
552
|
var posts = [
|
|
@@ -9641,7 +9647,7 @@ var siteExtractFn = inngest.createFunction(
|
|
|
9641
9647
|
});
|
|
9642
9648
|
}) : null;
|
|
9643
9649
|
const finalized = await step.run("finalize", async () => {
|
|
9644
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
9650
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-P2DTUVY3.js");
|
|
9645
9651
|
const current = await getExtractJob(jobId2);
|
|
9646
9652
|
if (!current) throw new Error("extract job disappeared before finalization");
|
|
9647
9653
|
const stored = await assembleExtractArtifacts(current, { branding, imageAudit });
|
|
@@ -10601,7 +10607,7 @@ async function resolveUsZipsPath(requestedPath) {
|
|
|
10601
10607
|
async function loadZipGroups(stateAbbr, requestedPath, warnings, sourceMode) {
|
|
10602
10608
|
const mode = resolvedLocationDataMode({ zipSource: sourceMode });
|
|
10603
10609
|
if (mode === "hosted") {
|
|
10604
|
-
const { getHostedZipGroups } = await import("./location-data-repository-
|
|
10610
|
+
const { getHostedZipGroups } = await import("./location-data-repository-AHKDXTEQ.js");
|
|
10605
10611
|
const hosted = await getHostedZipGroups(stateAbbr);
|
|
10606
10612
|
if (!hosted.dataset) {
|
|
10607
10613
|
throw new DirectoryLocationError(
|
|
@@ -10664,7 +10670,7 @@ async function resolveDirectoryMarkets(options, config = {}) {
|
|
|
10664
10670
|
const sourceUrl = censusStateUrl(state.fips);
|
|
10665
10671
|
const warnings = [];
|
|
10666
10672
|
if (resolvedLocationDataMode(config) === "hosted") {
|
|
10667
|
-
const { queryHostedLocationMarkets } = await import("./location-data-repository-
|
|
10673
|
+
const { queryHostedLocationMarkets } = await import("./location-data-repository-AHKDXTEQ.js");
|
|
10668
10674
|
const hosted = await queryHostedLocationMarkets({
|
|
10669
10675
|
state: state.abbr,
|
|
10670
10676
|
minPopulation: options.minPopulation,
|
|
@@ -12151,7 +12157,7 @@ function summarizePersistedLeadRows(rows, warnings = []) {
|
|
|
12151
12157
|
async function settlePersistedLeadListEnrichment(jobId2) {
|
|
12152
12158
|
const jobs = await listLeadListEnrichmentJobsNeedingSettlement(100);
|
|
12153
12159
|
const job = jobs.find((candidate) => candidate.id === jobId2);
|
|
12154
|
-
const { getLeadListEnrichmentJob: getLeadListEnrichmentJob2 } = await import("./lead-list-enrichment-repository-
|
|
12160
|
+
const { getLeadListEnrichmentJob: getLeadListEnrichmentJob2 } = await import("./lead-list-enrichment-repository-5LEWW4X7.js");
|
|
12155
12161
|
const current = job ?? await getLeadListEnrichmentJob2(jobId2);
|
|
12156
12162
|
if (!current) return null;
|
|
12157
12163
|
const rows = await listLeadListEnrichmentRows(jobId2);
|
|
@@ -12207,7 +12213,7 @@ async function reconcileLeadListEnrichmentSettlements(limit = 25) {
|
|
|
12207
12213
|
const persisted = job.result ?? summarizePersistedLeadRows(rows, job.warnings);
|
|
12208
12214
|
const status = job.cancelRequestedAt ? "cancelled" : persisted.failedRows > 0 && persisted.completeRows > 0 ? "partial" : persisted.failedRows > 0 ? "cancelled" : persisted.rowsWithContacts > 0 ? "complete" : "empty";
|
|
12209
12215
|
if (persisted.failedRows > 0 && persisted.completeRows === 0 && !job.cancelRequestedAt) {
|
|
12210
|
-
const { failLeadListEnrichmentJob: failLeadListEnrichmentJob2 } = await import("./lead-list-enrichment-repository-
|
|
12216
|
+
const { failLeadListEnrichmentJob: failLeadListEnrichmentJob2 } = await import("./lead-list-enrichment-repository-5LEWW4X7.js");
|
|
12211
12217
|
await failLeadListEnrichmentJob2({
|
|
12212
12218
|
jobId: job.id,
|
|
12213
12219
|
errorCode: "lead_list_all_rows_failed",
|
|
@@ -25939,6 +25945,7 @@ var CLEANUP_RESERVE_MS = 4e4;
|
|
|
25939
25945
|
var DIRECT_PAA_MAX_ATTEMPTS = 3;
|
|
25940
25946
|
var CHECKPOINT_INTERVAL_MS = 1e4;
|
|
25941
25947
|
var CHECKPOINT_IMPROVEMENT_THRESHOLD = 5;
|
|
25948
|
+
var LEASE_HEARTBEAT_MS = 1e4;
|
|
25942
25949
|
function normalizePaaQuestion(value) {
|
|
25943
25950
|
if (typeof value !== "string") return "";
|
|
25944
25951
|
return value.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[^\p{L}\p{N}\s]/gu, "").replace(/\s+/g, " ").trim();
|
|
@@ -25946,45 +25953,87 @@ function normalizePaaQuestion(value) {
|
|
|
25946
25953
|
function clean2(value) {
|
|
25947
25954
|
return typeof value === "string" ? value.trim() : "";
|
|
25948
25955
|
}
|
|
25956
|
+
function normalizeSource(value) {
|
|
25957
|
+
if (!value || typeof value !== "object") return null;
|
|
25958
|
+
const raw = value;
|
|
25959
|
+
const classified = classifyGoogleOutboundLink(clean2(raw.rawUrl) || clean2(raw.url), "https://www.google.com/");
|
|
25960
|
+
if (!classified) return null;
|
|
25961
|
+
return {
|
|
25962
|
+
...classified,
|
|
25963
|
+
url: clean2(raw.url) || classified.url,
|
|
25964
|
+
rawUrl: clean2(raw.rawUrl) || classified.rawUrl,
|
|
25965
|
+
resolvedUrl: clean2(raw.resolvedUrl) || classified.resolvedUrl,
|
|
25966
|
+
linkType: raw.linkType ?? classified.linkType,
|
|
25967
|
+
resolutionStatus: raw.resolutionStatus ?? classified.resolutionStatus,
|
|
25968
|
+
title: clean2(raw.title) || null,
|
|
25969
|
+
site: clean2(raw.site) || null
|
|
25970
|
+
};
|
|
25971
|
+
}
|
|
25972
|
+
function mergeSources(...groups) {
|
|
25973
|
+
const byRawUrl = /* @__PURE__ */ new Map();
|
|
25974
|
+
for (const value of groups.flat()) {
|
|
25975
|
+
const source = normalizeSource(value);
|
|
25976
|
+
if (!source) continue;
|
|
25977
|
+
const existing = byRawUrl.get(source.rawUrl);
|
|
25978
|
+
if (!existing || source.resolutionStatus === "resolved" && existing.resolutionStatus !== "resolved") {
|
|
25979
|
+
byRawUrl.set(source.rawUrl, source);
|
|
25980
|
+
} else {
|
|
25981
|
+
byRawUrl.set(source.rawUrl, { ...existing, title: existing.title ?? source.title, site: existing.site ?? source.site });
|
|
25982
|
+
}
|
|
25983
|
+
}
|
|
25984
|
+
return [...byRawUrl.values()];
|
|
25985
|
+
}
|
|
25949
25986
|
function durableRecordFromFlat(value) {
|
|
25950
25987
|
if (!value || typeof value !== "object") return null;
|
|
25951
25988
|
const row = value;
|
|
25952
25989
|
const question = clean2(row.question);
|
|
25953
25990
|
if (!normalizePaaQuestion(question)) return null;
|
|
25954
|
-
const
|
|
25955
|
-
const
|
|
25956
|
-
const
|
|
25957
|
-
|
|
25991
|
+
const durable = value;
|
|
25992
|
+
const sourceCite = clean2(row.source_cite) || clean2(durable.sourceCite);
|
|
25993
|
+
const sourceTitle = clean2(row.source_title) || clean2(durable.sourceTitle);
|
|
25994
|
+
const sourceSite = clean2(row.source_site) || clean2(durable.sourceSite);
|
|
25995
|
+
const legacySource = sourceCite ? normalizeSource({ title: sourceTitle, site: sourceSite, url: sourceCite, rawUrl: sourceCite }) : null;
|
|
25996
|
+
const sources = mergeSources(Array.isArray(row.sources) ? row.sources : [], legacySource ? [legacySource] : []);
|
|
25997
|
+
const primary = sources[0];
|
|
25998
|
+
return {
|
|
25999
|
+
questionId: clean2(row.question_id) || clean2(durable.questionId) || questionIdFor(question),
|
|
26000
|
+
googleLinkId: clean2(row.google_link_id) || clean2(durable.googleLinkId) || null,
|
|
26001
|
+
googleEvidenceId: clean2(row.google_evidence_id) || clean2(durable.googleEvidenceId) || null,
|
|
25958
26002
|
question,
|
|
25959
26003
|
answer: clean2(row.answer),
|
|
25960
|
-
sourceTitle,
|
|
25961
|
-
sourceSite,
|
|
25962
|
-
sourceCite,
|
|
25963
|
-
sources:
|
|
26004
|
+
sourceTitle: primary?.title ?? sourceTitle,
|
|
26005
|
+
sourceSite: primary?.site ?? sourceSite,
|
|
26006
|
+
sourceCite: primary?.url ?? sourceCite,
|
|
26007
|
+
sources: mergeSources(sources, Array.isArray(durable.sources) ? durable.sources : []),
|
|
25964
26008
|
depth: typeof row.depth === "number" && Number.isFinite(row.depth) ? row.depth : 1,
|
|
25965
26009
|
parentQuestion: clean2(row.parent_question) || null
|
|
25966
26010
|
};
|
|
25967
26011
|
}
|
|
25968
26012
|
function completenessRank(record2) {
|
|
25969
26013
|
const answer = Boolean(record2.answer.trim());
|
|
25970
|
-
const source = Boolean(record2.sourceCite.trim());
|
|
26014
|
+
const source = record2.sources.length > 0 || Boolean(record2.sourceCite.trim());
|
|
25971
26015
|
return answer && source ? 3 : answer ? 2 : source ? 1 : 0;
|
|
25972
26016
|
}
|
|
25973
26017
|
function sameRecord(left, right) {
|
|
25974
|
-
return left.question === right.question && left.answer === right.answer && left.sourceTitle === right.sourceTitle && left.sourceSite === right.sourceSite && left.sourceCite === right.sourceCite && left.depth === right.depth && left.parentQuestion === right.parentQuestion;
|
|
26018
|
+
return left.questionId === right.questionId && left.googleLinkId === right.googleLinkId && left.googleEvidenceId === right.googleEvidenceId && left.question === right.question && left.answer === right.answer && left.sourceTitle === right.sourceTitle && left.sourceSite === right.sourceSite && left.sourceCite === right.sourceCite && left.depth === right.depth && left.parentQuestion === right.parentQuestion && JSON.stringify(left.sources) === JSON.stringify(right.sources);
|
|
25975
26019
|
}
|
|
25976
26020
|
function fillMissing(primary, fallback) {
|
|
25977
|
-
const
|
|
25978
|
-
const
|
|
25979
|
-
const
|
|
26021
|
+
const sources = mergeSources(primary.sources, fallback.sources);
|
|
26022
|
+
const primarySource = sources[0];
|
|
26023
|
+
const sourceCite = primarySource?.url || primary.sourceCite || fallback.sourceCite;
|
|
26024
|
+
const sourceTitle = primarySource?.title || primary.sourceTitle || fallback.sourceTitle;
|
|
26025
|
+
const sourceSite = primarySource?.site || primary.sourceSite || fallback.sourceSite;
|
|
25980
26026
|
return {
|
|
25981
26027
|
...primary,
|
|
26028
|
+
questionId: primary.questionId || fallback.questionId,
|
|
26029
|
+
googleLinkId: primary.googleLinkId || fallback.googleLinkId,
|
|
26030
|
+
googleEvidenceId: primary.googleEvidenceId || fallback.googleEvidenceId,
|
|
25982
26031
|
question: primary.question || fallback.question,
|
|
25983
26032
|
answer: primary.answer || fallback.answer,
|
|
25984
26033
|
sourceTitle,
|
|
25985
26034
|
sourceSite,
|
|
25986
26035
|
sourceCite,
|
|
25987
|
-
sources
|
|
26036
|
+
sources,
|
|
25988
26037
|
depth: Number.isFinite(primary.depth) ? primary.depth : fallback.depth,
|
|
25989
26038
|
parentQuestion: primary.parentQuestion || fallback.parentQuestion
|
|
25990
26039
|
};
|
|
@@ -26003,23 +26052,28 @@ function mergePaaProgressRecord(existing, incoming, attempt, observedAt) {
|
|
|
26003
26052
|
function flatFromRecord(record2, seedQuery) {
|
|
26004
26053
|
return {
|
|
26005
26054
|
seed_query: seedQuery,
|
|
26055
|
+
question_id: record2.questionId,
|
|
26056
|
+
google_link_id: record2.googleLinkId ?? "",
|
|
26057
|
+
google_evidence_id: record2.googleEvidenceId ?? "",
|
|
26006
26058
|
question: record2.question,
|
|
26007
26059
|
answer: record2.answer,
|
|
26008
26060
|
source_title: record2.sourceTitle,
|
|
26009
26061
|
source_site: record2.sourceSite,
|
|
26010
26062
|
source_cite: record2.sourceCite,
|
|
26063
|
+
sources: record2.sources,
|
|
26011
26064
|
depth: record2.depth,
|
|
26012
26065
|
parent_question: record2.parentQuestion ?? "",
|
|
26013
26066
|
extracted_at: record2.observedAt
|
|
26014
26067
|
};
|
|
26015
26068
|
}
|
|
26016
26069
|
var ProgressivePaaCheckpoint = class {
|
|
26017
|
-
constructor(jobId2, durableMetadata, persist
|
|
26070
|
+
constructor(jobId2, durableMetadata, persist, now = Date.now, initialResult) {
|
|
26018
26071
|
this.jobId = jobId2;
|
|
26019
26072
|
this.durableMetadata = durableMetadata;
|
|
26020
26073
|
this.persist = persist;
|
|
26021
26074
|
this.now = now;
|
|
26022
26075
|
this.lastPersistedAt = now();
|
|
26076
|
+
this.hydrate(initialResult);
|
|
26023
26077
|
}
|
|
26024
26078
|
jobId;
|
|
26025
26079
|
durableMetadata;
|
|
@@ -26028,10 +26082,34 @@ var ProgressivePaaCheckpoint = class {
|
|
|
26028
26082
|
records = /* @__PURE__ */ new Map();
|
|
26029
26083
|
clickedQuestions = /* @__PURE__ */ new Set();
|
|
26030
26084
|
interruptions = [];
|
|
26085
|
+
lifecycle = null;
|
|
26086
|
+
material = null;
|
|
26031
26087
|
sequence = 0;
|
|
26032
26088
|
attempt = 1;
|
|
26033
26089
|
improvementsSinceWrite = 0;
|
|
26034
26090
|
lastPersistedAt;
|
|
26091
|
+
hydrate(initialResult) {
|
|
26092
|
+
if (!initialResult || typeof initialResult !== "object") return;
|
|
26093
|
+
const progress = initialResult.progress;
|
|
26094
|
+
if (!progress || typeof progress !== "object") return;
|
|
26095
|
+
const value = progress;
|
|
26096
|
+
this.sequence = Number.isFinite(value.sequence) ? Math.max(0, Number(value.sequence)) : 0;
|
|
26097
|
+
this.attempt = Number.isFinite(value.attempt) ? Math.max(1, Number(value.attempt)) : 1;
|
|
26098
|
+
for (const question of value.clickedQuestions ?? []) if (clean2(question)) this.clickedQuestions.add(clean2(question));
|
|
26099
|
+
for (const interruption of value.interruptions ?? []) this.interruptions.push(interruption);
|
|
26100
|
+
if (value.lifecycle) this.lifecycle = { ...value.lifecycle };
|
|
26101
|
+
if (value.material) this.material = structuredClone(value.material);
|
|
26102
|
+
for (const raw of value.records ?? []) {
|
|
26103
|
+
const incoming = durableRecordFromFlat(raw);
|
|
26104
|
+
if (!incoming) continue;
|
|
26105
|
+
const record2 = raw;
|
|
26106
|
+
this.records.set(normalizePaaQuestion(incoming.question), {
|
|
26107
|
+
...incoming,
|
|
26108
|
+
attempts: Array.isArray(record2.attempts) ? record2.attempts.filter(Number.isFinite) : [this.attempt],
|
|
26109
|
+
observedAt: clean2(record2.observedAt) || new Date(this.now()).toISOString()
|
|
26110
|
+
});
|
|
26111
|
+
}
|
|
26112
|
+
}
|
|
26035
26113
|
setAttempt(attempt) {
|
|
26036
26114
|
this.attempt = Math.max(1, attempt);
|
|
26037
26115
|
}
|
|
@@ -26050,6 +26128,11 @@ var ProgressivePaaCheckpoint = class {
|
|
|
26050
26128
|
}
|
|
26051
26129
|
accept(snapshot) {
|
|
26052
26130
|
this.sequence += 1;
|
|
26131
|
+
if (snapshot.lifecycle) this.lifecycle = { ...snapshot.lifecycle };
|
|
26132
|
+
if (snapshot.material) {
|
|
26133
|
+
this.material = structuredClone(snapshot.material);
|
|
26134
|
+
this.improvementsSinceWrite += 1;
|
|
26135
|
+
}
|
|
26053
26136
|
for (const question of snapshot.clickedQuestions) if (clean2(question)) this.clickedQuestions.add(clean2(question));
|
|
26054
26137
|
for (const raw of snapshot.records) {
|
|
26055
26138
|
const incoming = durableRecordFromFlat(raw);
|
|
@@ -26074,6 +26157,9 @@ var ProgressivePaaCheckpoint = class {
|
|
|
26074
26157
|
hasRows() {
|
|
26075
26158
|
return this.records.size > 0;
|
|
26076
26159
|
}
|
|
26160
|
+
hasPreservedMaterial() {
|
|
26161
|
+
return this.records.size > 0 || this.material !== null;
|
|
26162
|
+
}
|
|
26077
26163
|
rows() {
|
|
26078
26164
|
return [...this.records.values()];
|
|
26079
26165
|
}
|
|
@@ -26089,7 +26175,9 @@ var ProgressivePaaCheckpoint = class {
|
|
|
26089
26175
|
captchaObserved: false,
|
|
26090
26176
|
solverCleared: false,
|
|
26091
26177
|
error,
|
|
26092
|
-
interruptions: [...this.interruptions]
|
|
26178
|
+
interruptions: [...this.interruptions],
|
|
26179
|
+
lifecycle: this.lifecycle ? { ...this.lifecycle } : null,
|
|
26180
|
+
material: this.material ? structuredClone(this.material) : null
|
|
26093
26181
|
};
|
|
26094
26182
|
}
|
|
26095
26183
|
async flush(phase, options = {}) {
|
|
@@ -26106,11 +26194,12 @@ var ProgressivePaaCheckpoint = class {
|
|
|
26106
26194
|
return true;
|
|
26107
26195
|
}
|
|
26108
26196
|
};
|
|
26109
|
-
function partialTerminalResult(job, options, maxQuestions, progress) {
|
|
26197
|
+
function partialTerminalResult(job, options, maxQuestions, progress, recoveryCount) {
|
|
26110
26198
|
const flat = progress.records.map((record2) => flatFromRecord(record2, options.query ?? job.query));
|
|
26111
26199
|
const withoutAnswer = flat.filter((row) => !row.answer).length;
|
|
26112
|
-
const withoutSource = flat.filter((row) => !row.source_cite).length;
|
|
26200
|
+
const withoutSource = flat.filter((row) => row.sources.length === 0 && !row.source_cite).length;
|
|
26113
26201
|
const latestInterruption = progress.interruptions.at(-1);
|
|
26202
|
+
const material = progress.material;
|
|
26114
26203
|
return {
|
|
26115
26204
|
seed: options.query ?? job.query,
|
|
26116
26205
|
location: options.location ?? null,
|
|
@@ -26118,22 +26207,40 @@ function partialTerminalResult(job, options, maxQuestions, progress) {
|
|
|
26118
26207
|
totalQuestions: flat.length,
|
|
26119
26208
|
tree: [],
|
|
26120
26209
|
flat,
|
|
26121
|
-
videos: [],
|
|
26122
|
-
forums: [],
|
|
26123
|
-
organicResults: [],
|
|
26124
|
-
localPack: [],
|
|
26125
|
-
whatPeopleSaying: [],
|
|
26126
|
-
aiOverview: { detected: false, text: null, citations: [] },
|
|
26127
|
-
aiMode: { detected: false, text: null, citations: [] },
|
|
26128
|
-
entityIds: { entities: [], kgIds: [], cids: [], gcids: [] },
|
|
26129
|
-
surface: "unknown",
|
|
26210
|
+
videos: material?.videos ?? [],
|
|
26211
|
+
forums: material?.forums ?? [],
|
|
26212
|
+
organicResults: material?.organicResults ?? [],
|
|
26213
|
+
localPack: material?.localPack ?? [],
|
|
26214
|
+
whatPeopleSaying: material?.whatPeopleSaying ?? [],
|
|
26215
|
+
aiOverview: material?.aiOverview ?? { detected: false, text: null, citations: [] },
|
|
26216
|
+
aiMode: material?.aiMode ?? { detected: false, text: null, citations: [] },
|
|
26217
|
+
entityIds: material?.entityIds ?? { entities: [], kgIds: [], cids: [], gcids: [] },
|
|
26218
|
+
surface: material?.surface ?? "unknown",
|
|
26130
26219
|
stats: { seed: options.query ?? job.query, totalQuestions: flat.length, maxDepthReached: 1, durationMs: 0, errorCount: 1 },
|
|
26131
26220
|
diagnostics: {
|
|
26132
26221
|
completionStatus: "paa_found",
|
|
26133
26222
|
problem: null,
|
|
26134
26223
|
resultQuality: "partial",
|
|
26135
26224
|
degradedResult: false,
|
|
26136
|
-
retryRecommended:
|
|
26225
|
+
retryRecommended: true,
|
|
26226
|
+
paaLifecycle: {
|
|
26227
|
+
...progress.lifecycle ?? {
|
|
26228
|
+
requestedQuestions: maxQuestions,
|
|
26229
|
+
questionsFound: flat.length,
|
|
26230
|
+
targetStatus: flat.length >= maxQuestions ? "met" : "not_met",
|
|
26231
|
+
materialStatus: "partial",
|
|
26232
|
+
knownQuestions: flat.length,
|
|
26233
|
+
processedQuestions: progress.clickedQuestions.length,
|
|
26234
|
+
failedInteractions: 0,
|
|
26235
|
+
noGrowthConfirmations: 0
|
|
26236
|
+
},
|
|
26237
|
+
questionsFound: flat.length,
|
|
26238
|
+
targetStatus: flat.length >= maxQuestions ? "met" : "not_met",
|
|
26239
|
+
discoveryStatus: "recovery_exhausted",
|
|
26240
|
+
materialStatus: "partial",
|
|
26241
|
+
completionReason: "Automatic runtime recovery was exhausted; all preserved material is returned.",
|
|
26242
|
+
automaticRetries: recoveryCount + progress.interruptions.filter((value) => value.willRetry).length
|
|
26243
|
+
},
|
|
26137
26244
|
completeness: {
|
|
26138
26245
|
paaWithoutAnswer: withoutAnswer,
|
|
26139
26246
|
paaWithoutSource: withoutSource,
|
|
@@ -26143,7 +26250,7 @@ function partialTerminalResult(job, options, maxQuestions, progress) {
|
|
|
26143
26250
|
paaReturned: flat.length,
|
|
26144
26251
|
paaUnique: flat.length
|
|
26145
26252
|
},
|
|
26146
|
-
warnings: [{ code: "paa_partial", surface: "paa", message: "
|
|
26253
|
+
warnings: [{ code: "paa_partial", surface: "paa", message: "Automatic recovery ended before frontier exhaustion could be proven; preserved material is returned.", retryable: true }],
|
|
26147
26254
|
...latestInterruption && ["browser_session_interrupted", "request_aborted", "timeout"].includes(latestInterruption.outcome) ? { interruption: { code: latestInterruption.outcome, reasonSource: latestInterruption.reasonSource, message: null } } : {}
|
|
26148
26255
|
},
|
|
26149
26256
|
progress,
|
|
@@ -26171,21 +26278,36 @@ async function settleCompletedJob(jobId2) {
|
|
|
26171
26278
|
}
|
|
26172
26279
|
async function runPaaHarvestJob(jobId2) {
|
|
26173
26280
|
const invocationStartedAt = Date.now();
|
|
26174
|
-
const
|
|
26175
|
-
if (!
|
|
26281
|
+
const claim = await claimDurablePaaJob(jobId2);
|
|
26282
|
+
if (!claim) return { jobId: jobId2, status: "missing_or_not_paa" };
|
|
26283
|
+
const { job, leaseToken, recoveryCount } = claim;
|
|
26176
26284
|
if (job.status === "done" || job.status === "failed" || job.status === "cancelled") {
|
|
26177
26285
|
await settleCompletedJob(job.id);
|
|
26178
26286
|
return { jobId: job.id, status: job.status };
|
|
26179
26287
|
}
|
|
26288
|
+
if (!leaseToken) return { jobId: job.id, status: "missing_lease" };
|
|
26180
26289
|
const options = job.options;
|
|
26181
26290
|
const maxQuestions = Math.max(1, Math.min(100, Number(options.maxQuestions ?? 30)));
|
|
26182
26291
|
const timeoutBudget = harvestTimeoutBudget(maxQuestions);
|
|
26183
26292
|
const workBudgetMs = Math.max(1, timeoutBudget.serverMs - CLEANUP_RESERVE_MS);
|
|
26184
|
-
const progress = new ProgressivePaaCheckpoint(
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
|
|
26188
|
-
|
|
26293
|
+
const progress = new ProgressivePaaCheckpoint(
|
|
26294
|
+
job.id,
|
|
26295
|
+
{
|
|
26296
|
+
invocationBudgetMs: timeoutBudget.serverMs,
|
|
26297
|
+
workBudgetMs,
|
|
26298
|
+
cleanupReserveMs: CLEANUP_RESERVE_MS,
|
|
26299
|
+
recoveryCount
|
|
26300
|
+
},
|
|
26301
|
+
(_id, result2) => checkpointDurablePaaJob(job.id, leaseToken, result2),
|
|
26302
|
+
Date.now,
|
|
26303
|
+
job.result
|
|
26304
|
+
);
|
|
26305
|
+
const heartbeat = setInterval(() => {
|
|
26306
|
+
void renewDurablePaaLease(job.id, leaseToken).catch((error) => {
|
|
26307
|
+
console.error("[paa-harvest] lease heartbeat failed:", error instanceof Error ? error.message : String(error));
|
|
26308
|
+
});
|
|
26309
|
+
}, LEASE_HEARTBEAT_MS);
|
|
26310
|
+
heartbeat.unref?.();
|
|
26189
26311
|
try {
|
|
26190
26312
|
if (!brightDataSerpEnabled()) throw new Error("SERP browser service is not configured");
|
|
26191
26313
|
await progress.flush("navigating", { force: true });
|
|
@@ -26238,8 +26360,12 @@ async function runPaaHarvestJob(jobId2) {
|
|
|
26238
26360
|
const rawDiagnostics = harvestResult.diagnostics && typeof harvestResult.diagnostics === "object" ? harvestResult.diagnostics : {};
|
|
26239
26361
|
const rawCompleteness = rawDiagnostics.completeness && typeof rawDiagnostics.completeness === "object" ? rawDiagnostics.completeness : {};
|
|
26240
26362
|
const missingAnswers = mergedFlat.filter((row) => !row.answer).length;
|
|
26241
|
-
const missingSources = mergedFlat.filter((row) => !row.source_cite).length;
|
|
26242
|
-
const
|
|
26363
|
+
const missingSources = mergedFlat.filter((row) => row.sources.length === 0 && !row.source_cite).length;
|
|
26364
|
+
const rawLifecycle = rawDiagnostics.paaLifecycle && typeof rawDiagnostics.paaLifecycle === "object" ? rawDiagnostics.paaLifecycle : {};
|
|
26365
|
+
const discoveryStatus = typeof rawLifecycle.discoveryStatus === "string" ? rawLifecycle.discoveryStatus : "interrupted";
|
|
26366
|
+
const materialPartial = missingAnswers > 0 || missingSources > 0;
|
|
26367
|
+
const incomplete = discoveryStatus === "interrupted" || discoveryStatus === "recovery_exhausted" || materialPartial;
|
|
26368
|
+
const automaticRetries = recoveryCount + terminalProgress.interruptions.filter((value) => value.willRetry).length;
|
|
26243
26369
|
const result2 = {
|
|
26244
26370
|
...harvestResult,
|
|
26245
26371
|
totalQuestions: mergedFlat.length,
|
|
@@ -26247,7 +26373,17 @@ async function runPaaHarvestJob(jobId2) {
|
|
|
26247
26373
|
stats: harvestResult.stats && typeof harvestResult.stats === "object" ? { ...harvestResult.stats, totalQuestions: mergedFlat.length } : harvestResult.stats,
|
|
26248
26374
|
diagnostics: {
|
|
26249
26375
|
...rawDiagnostics,
|
|
26250
|
-
|
|
26376
|
+
resultQuality: incomplete ? "partial" : "complete",
|
|
26377
|
+
degradedResult: false,
|
|
26378
|
+
retryRecommended: discoveryStatus === "interrupted" || discoveryStatus === "recovery_exhausted",
|
|
26379
|
+
paaLifecycle: {
|
|
26380
|
+
...rawLifecycle,
|
|
26381
|
+
requestedQuestions: maxQuestions,
|
|
26382
|
+
questionsFound: mergedFlat.length,
|
|
26383
|
+
targetStatus: mergedFlat.length >= maxQuestions ? "met" : "not_met",
|
|
26384
|
+
materialStatus: materialPartial ? "partial" : "complete",
|
|
26385
|
+
automaticRetries
|
|
26386
|
+
},
|
|
26251
26387
|
completeness: {
|
|
26252
26388
|
...rawCompleteness,
|
|
26253
26389
|
paaWithoutAnswer: missingAnswers,
|
|
@@ -26267,7 +26403,7 @@ async function runPaaHarvestJob(jobId2) {
|
|
|
26267
26403
|
rawDomArtifactStatus: "unavailable"
|
|
26268
26404
|
}
|
|
26269
26405
|
};
|
|
26270
|
-
if (!await
|
|
26406
|
+
if (!await completeDurablePaaJob(job.id, leaseToken, result2)) throw new Error("job_left_running_state_during_capture");
|
|
26271
26407
|
await settleCompletedJob(job.id);
|
|
26272
26408
|
if (job.callback_url) await deliverWebhook(job.callback_url, { job_id: job.id, status: "done", result: result2 });
|
|
26273
26409
|
return { jobId: job.id, status: "done", totalQuestions: questionCount(result2), partial: incomplete, artifactStored: false };
|
|
@@ -26276,16 +26412,16 @@ async function runPaaHarvestJob(jobId2) {
|
|
|
26276
26412
|
const privateError = serializeHarvestProblem(problem);
|
|
26277
26413
|
await progress.flush("failed", { force: true, error: privateError }).catch(() => {
|
|
26278
26414
|
});
|
|
26279
|
-
if (progress.
|
|
26415
|
+
if (progress.hasPreservedMaterial()) {
|
|
26280
26416
|
const terminalProgress = progress.checkpoint("failed", privateError);
|
|
26281
|
-
const result2 = partialTerminalResult(job, options, maxQuestions, terminalProgress);
|
|
26282
|
-
if (await
|
|
26417
|
+
const result2 = partialTerminalResult(job, options, maxQuestions, terminalProgress, recoveryCount);
|
|
26418
|
+
if (await completeDurablePaaJob(job.id, leaseToken, result2)) {
|
|
26283
26419
|
await settleCompletedJob(job.id);
|
|
26284
26420
|
if (job.callback_url) await deliverWebhook(job.callback_url, { job_id: job.id, status: "done", result: result2 });
|
|
26285
26421
|
return { jobId: job.id, status: "done", totalQuestions: questionCount(result2), partial: true, artifactStored: false };
|
|
26286
26422
|
}
|
|
26287
26423
|
}
|
|
26288
|
-
await
|
|
26424
|
+
await failDurablePaaJob(job.id, leaseToken, privateError, harvestProblemEnvelope(problem, { chargeStatus: "refund_pending" }));
|
|
26289
26425
|
await settlePaaHarvestJob(job.id).then(async (settled) => {
|
|
26290
26426
|
if (!settled) return;
|
|
26291
26427
|
const settledJob = await getJob(job.id);
|
|
@@ -26303,6 +26439,8 @@ async function runPaaHarvestJob(jobId2) {
|
|
|
26303
26439
|
});
|
|
26304
26440
|
}
|
|
26305
26441
|
throw error;
|
|
26442
|
+
} finally {
|
|
26443
|
+
clearInterval(heartbeat);
|
|
26306
26444
|
}
|
|
26307
26445
|
}
|
|
26308
26446
|
|
|
@@ -26501,22 +26639,48 @@ function recoverableRecords(result2) {
|
|
|
26501
26639
|
questions.set(question, record2);
|
|
26502
26640
|
continue;
|
|
26503
26641
|
}
|
|
26504
|
-
const
|
|
26505
|
-
|
|
26642
|
+
const sourcesOf = (value) => Array.isArray(value.sources) ? value.sources.filter((source) => source && typeof source === "object") : [];
|
|
26643
|
+
const completeness = (value) => {
|
|
26644
|
+
const sources = sourcesOf(value);
|
|
26645
|
+
return Number(Boolean(String(value.answer ?? "").trim())) * 4 + Number(sources.length > 0 || Boolean(String(value.sourceCite ?? value.source_cite ?? "").trim())) * 2 + sources.filter((source) => source.resolutionStatus === "resolved").length;
|
|
26646
|
+
};
|
|
26647
|
+
const preferred = completeness(record2) >= completeness(existing) ? record2 : existing;
|
|
26648
|
+
const fallback = preferred === record2 ? existing : record2;
|
|
26649
|
+
const mergedSources = /* @__PURE__ */ new Map();
|
|
26650
|
+
for (const source of [...sourcesOf(fallback), ...sourcesOf(preferred)]) {
|
|
26651
|
+
const key2 = String(source.rawUrl ?? source.url ?? "");
|
|
26652
|
+
if (!key2) continue;
|
|
26653
|
+
const current = mergedSources.get(key2);
|
|
26654
|
+
if (!current || source.resolutionStatus === "resolved") mergedSources.set(key2, source);
|
|
26655
|
+
}
|
|
26656
|
+
questions.set(question, {
|
|
26657
|
+
...fallback,
|
|
26658
|
+
...preferred,
|
|
26659
|
+
questionId: String(preferred.questionId ?? fallback.questionId ?? questionIdFor(String(preferred.question ?? fallback.question ?? ""))),
|
|
26660
|
+
googleLinkId: preferred.googleLinkId ?? fallback.googleLinkId ?? null,
|
|
26661
|
+
googleEvidenceId: preferred.googleEvidenceId ?? fallback.googleEvidenceId ?? null,
|
|
26662
|
+
sources: [...mergedSources.values()]
|
|
26663
|
+
});
|
|
26506
26664
|
}
|
|
26507
26665
|
return [...questions.values()];
|
|
26508
26666
|
}
|
|
26509
|
-
function stalePartialResult(result2, records, seedQuery) {
|
|
26667
|
+
function stalePartialResult(result2, records, seedQuery, recoveryCount) {
|
|
26510
26668
|
const current = result2 && typeof result2 === "object" ? result2 : {};
|
|
26669
|
+
const progress = current.progress && typeof current.progress === "object" ? current.progress : {};
|
|
26670
|
+
const material = progress.material && typeof progress.material === "object" ? progress.material : {};
|
|
26511
26671
|
const diagnostics = current.diagnostics && typeof current.diagnostics === "object" ? current.diagnostics : {};
|
|
26512
26672
|
const completeness = diagnostics.completeness && typeof diagnostics.completeness === "object" ? diagnostics.completeness : {};
|
|
26513
26673
|
const flat = records.map((record2) => ({
|
|
26514
26674
|
seed_query: typeof record2.seed_query === "string" ? record2.seed_query : seedQuery,
|
|
26675
|
+
question_id: typeof record2.question_id === "string" ? record2.question_id : typeof record2.questionId === "string" ? record2.questionId : questionIdFor(String(record2.question ?? "")),
|
|
26676
|
+
google_link_id: typeof record2.google_link_id === "string" ? record2.google_link_id : typeof record2.googleLinkId === "string" ? record2.googleLinkId : "",
|
|
26677
|
+
google_evidence_id: typeof record2.google_evidence_id === "string" ? record2.google_evidence_id : typeof record2.googleEvidenceId === "string" ? record2.googleEvidenceId : "",
|
|
26515
26678
|
question: typeof record2.question === "string" ? record2.question : "",
|
|
26516
26679
|
answer: typeof record2.answer === "string" ? record2.answer : "",
|
|
26517
26680
|
source_title: typeof record2.source_title === "string" ? record2.source_title : typeof record2.sourceTitle === "string" ? record2.sourceTitle : "",
|
|
26518
26681
|
source_site: typeof record2.source_site === "string" ? record2.source_site : typeof record2.sourceSite === "string" ? record2.sourceSite : "",
|
|
26519
26682
|
source_cite: typeof record2.source_cite === "string" ? record2.source_cite : typeof record2.sourceCite === "string" ? record2.sourceCite : "",
|
|
26683
|
+
sources: Array.isArray(record2.sources) ? record2.sources : [],
|
|
26520
26684
|
depth: typeof record2.depth === "number" ? record2.depth : 1,
|
|
26521
26685
|
parent_question: typeof record2.parent_question === "string" ? record2.parent_question : typeof record2.parentQuestion === "string" ? record2.parentQuestion : "",
|
|
26522
26686
|
extracted_at: typeof record2.extracted_at === "string" ? record2.extracted_at : typeof record2.observedAt === "string" ? record2.observedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -26527,6 +26691,15 @@ function stalePartialResult(result2, records, seedQuery) {
|
|
|
26527
26691
|
totalQuestions: uniqueCount,
|
|
26528
26692
|
flat,
|
|
26529
26693
|
tree: Array.isArray(current.tree) ? current.tree : [],
|
|
26694
|
+
videos: Array.isArray(material.videos) ? material.videos : current.videos ?? [],
|
|
26695
|
+
forums: Array.isArray(material.forums) ? material.forums : current.forums ?? [],
|
|
26696
|
+
organicResults: Array.isArray(material.organicResults) ? material.organicResults : current.organicResults ?? [],
|
|
26697
|
+
localPack: Array.isArray(material.localPack) ? material.localPack : current.localPack ?? [],
|
|
26698
|
+
whatPeopleSaying: Array.isArray(material.whatPeopleSaying) ? material.whatPeopleSaying : current.whatPeopleSaying ?? [],
|
|
26699
|
+
aiOverview: material.aiOverview ?? current.aiOverview,
|
|
26700
|
+
aiMode: material.aiMode ?? current.aiMode,
|
|
26701
|
+
entityIds: material.entityIds ?? current.entityIds,
|
|
26702
|
+
surface: material.surface ?? current.surface,
|
|
26530
26703
|
partial: true,
|
|
26531
26704
|
diagnostics: {
|
|
26532
26705
|
...diagnostics,
|
|
@@ -26534,7 +26707,17 @@ function stalePartialResult(result2, records, seedQuery) {
|
|
|
26534
26707
|
problem: null,
|
|
26535
26708
|
resultQuality: "partial",
|
|
26536
26709
|
degradedResult: false,
|
|
26537
|
-
retryRecommended:
|
|
26710
|
+
retryRecommended: true,
|
|
26711
|
+
paaLifecycle: {
|
|
26712
|
+
...diagnostics.paaLifecycle && typeof diagnostics.paaLifecycle === "object" ? diagnostics.paaLifecycle : {},
|
|
26713
|
+
requestedQuestions: Number(completeness.paaRequested ?? uniqueCount),
|
|
26714
|
+
questionsFound: uniqueCount,
|
|
26715
|
+
targetStatus: uniqueCount >= Number(completeness.paaRequested ?? Number.MAX_SAFE_INTEGER) ? "met" : "not_met",
|
|
26716
|
+
discoveryStatus: "recovery_exhausted",
|
|
26717
|
+
materialStatus: "partial",
|
|
26718
|
+
completionReason: "Automatic runtime recovery was exhausted; all preserved material is returned.",
|
|
26719
|
+
automaticRetries: recoveryCount
|
|
26720
|
+
},
|
|
26538
26721
|
interruption: {
|
|
26539
26722
|
code: "timeout",
|
|
26540
26723
|
reasonSource: "client_runtime",
|
|
@@ -26553,7 +26736,16 @@ function stalePartialResult(result2, records, seedQuery) {
|
|
|
26553
26736
|
}
|
|
26554
26737
|
};
|
|
26555
26738
|
}
|
|
26556
|
-
|
|
26739
|
+
var MAX_RUNTIME_RECOVERIES = 2;
|
|
26740
|
+
async function dispatchRecovery(origin, jobId2) {
|
|
26741
|
+
if (!process.env.CRON_SECRET) return false;
|
|
26742
|
+
const response = await fetch(`${origin}/harvest/internal/resume/${encodeURIComponent(jobId2)}`, {
|
|
26743
|
+
method: "POST",
|
|
26744
|
+
headers: { Authorization: `Bearer ${process.env.CRON_SECRET}` }
|
|
26745
|
+
});
|
|
26746
|
+
return response.ok || response.status === 409;
|
|
26747
|
+
}
|
|
26748
|
+
async function reconcilePaaHarvestSettlements(limit = 25, origin) {
|
|
26557
26749
|
let providerChecked = 0;
|
|
26558
26750
|
let providerCompleted = 0;
|
|
26559
26751
|
let providerFailed = 0;
|
|
@@ -26565,19 +26757,32 @@ async function reconcilePaaHarvestSettlements(limit = 25) {
|
|
|
26565
26757
|
} catch {
|
|
26566
26758
|
providerFailed = 1;
|
|
26567
26759
|
}
|
|
26568
|
-
const stale = await
|
|
26760
|
+
const stale = await listRecoverableDurablePaaJobs(limit);
|
|
26569
26761
|
let stalePartial = 0;
|
|
26570
26762
|
let staleFailed = 0;
|
|
26763
|
+
let requeued = 0;
|
|
26764
|
+
let redispatched = 0;
|
|
26571
26765
|
for (const job of stale) {
|
|
26572
26766
|
try {
|
|
26767
|
+
const recoveryCount = Math.max(0, Number(job.options.paaRecoveryCount ?? 0));
|
|
26768
|
+
if (job.status === "pending") {
|
|
26769
|
+
if (origin && await dispatchRecovery(origin, job.id)) redispatched += 1;
|
|
26770
|
+
continue;
|
|
26771
|
+
}
|
|
26772
|
+
if (recoveryCount < MAX_RUNTIME_RECOVERIES && await requeueExpiredDurablePaaJob(job.id, MAX_RUNTIME_RECOVERIES)) {
|
|
26773
|
+
requeued += 1;
|
|
26774
|
+
if (origin && await dispatchRecovery(origin, job.id)) redispatched += 1;
|
|
26775
|
+
continue;
|
|
26776
|
+
}
|
|
26573
26777
|
const retained = recoverableRecords(job.result);
|
|
26574
|
-
|
|
26575
|
-
|
|
26778
|
+
const progress = job.result && typeof job.result === "object" ? job.result.progress : void 0;
|
|
26779
|
+
if (retained.length > 0 || Boolean(progress?.material)) {
|
|
26780
|
+
if (await completeExpiredDurablePaaJob(job.id, stalePartialResult(job.result, retained, job.query, recoveryCount))) stalePartial += 1;
|
|
26576
26781
|
continue;
|
|
26577
26782
|
}
|
|
26578
|
-
const privateError = "
|
|
26783
|
+
const privateError = "PAA runtime recovery was exhausted; no recoverable rows were retained";
|
|
26579
26784
|
const problem = classifyHarvestProblem(new Error("harvest timeout"));
|
|
26580
|
-
if (await
|
|
26785
|
+
if (await failExpiredDurablePaaJob(job.id, privateError, harvestProblemEnvelope(problem, { chargeStatus: "refund_pending" }))) {
|
|
26581
26786
|
staleFailed += 1;
|
|
26582
26787
|
}
|
|
26583
26788
|
} catch {
|
|
@@ -26607,6 +26812,8 @@ async function reconcilePaaHarvestSettlements(limit = 25) {
|
|
|
26607
26812
|
checked: jobs.length,
|
|
26608
26813
|
stalePartial,
|
|
26609
26814
|
staleFailed,
|
|
26815
|
+
requeued,
|
|
26816
|
+
redispatched,
|
|
26610
26817
|
settled,
|
|
26611
26818
|
failed,
|
|
26612
26819
|
providerChecked,
|
|
@@ -42270,7 +42477,7 @@ async function prepareCommonsEntity(input, user) {
|
|
|
42270
42477
|
const duplicateCandidates = await potentialDuplicateCandidates({
|
|
42271
42478
|
title,
|
|
42272
42479
|
slug: slug4,
|
|
42273
|
-
source:
|
|
42480
|
+
source: normalizeSource2(input.source),
|
|
42274
42481
|
maxCandidates: clampNumber(input.maxCandidates, 1, 20, 8)
|
|
42275
42482
|
});
|
|
42276
42483
|
const tagVocabulary = await commonsTagVocabulary();
|
|
@@ -42324,7 +42531,7 @@ async function validateCommonsEntity(input, user) {
|
|
|
42324
42531
|
const description = optionalText2(input.description, 600);
|
|
42325
42532
|
const slug4 = normalizeSlug(input.slug || title || "");
|
|
42326
42533
|
const contract = commonsEntityProfileFor(input.entityType, input.seo?.schemaOrgType);
|
|
42327
|
-
const source =
|
|
42534
|
+
const source = normalizeSource2(input.source);
|
|
42328
42535
|
const featuredImage = normalizeFeaturedImage(input.featuredImage);
|
|
42329
42536
|
const normalizedFeaturedImageUrl = featuredImage?.url ? normalizeCommonsImageUrl(featuredImage.url) : null;
|
|
42330
42537
|
const registeredFeaturedImage = normalizedFeaturedImageUrl ? await findCommonsHostedImageByUrl(normalizedFeaturedImageUrl) : null;
|
|
@@ -43066,7 +43273,7 @@ function normalizeSubmitInput(input) {
|
|
|
43066
43273
|
entityType: normalizeEntityType(input.entityType),
|
|
43067
43274
|
disambiguationName: optionalText2(input.disambiguationName, 240) ?? void 0,
|
|
43068
43275
|
featuredImage: normalizeFeaturedImage(input.featuredImage),
|
|
43069
|
-
source:
|
|
43276
|
+
source: normalizeSource2(input.source),
|
|
43070
43277
|
tags: uniqueStrings(input.tags ?? []).slice(0, 24),
|
|
43071
43278
|
keywords: uniqueStrings(input.keywords ?? []).slice(0, 50),
|
|
43072
43279
|
relatedEntities: normalizeRelatedEntities(input.relatedEntities),
|
|
@@ -43687,7 +43894,7 @@ function normalizeMedia(media, featuredImage) {
|
|
|
43687
43894
|
return true;
|
|
43688
43895
|
}).slice(0, 300);
|
|
43689
43896
|
}
|
|
43690
|
-
function
|
|
43897
|
+
function normalizeSource2(source) {
|
|
43691
43898
|
return {
|
|
43692
43899
|
originalUrl: optionalText2(source?.originalUrl, 2e3) ?? void 0,
|
|
43693
43900
|
resolvedUrl: optionalText2(source?.resolvedUrl, 2e3) ?? void 0,
|
|
@@ -47156,7 +47363,7 @@ async function callMainOwnedExportPage(identity, input) {
|
|
|
47156
47363
|
});
|
|
47157
47364
|
}
|
|
47158
47365
|
if (connection.providerConfigKey === "google-mail" && input.dataset === "emails") {
|
|
47159
|
-
const { GmailService: GmailService2 } = await import("./gmail-service-
|
|
47366
|
+
const { GmailService: GmailService2 } = await import("./gmail-service-HN57R2GS.js");
|
|
47160
47367
|
const service = new GmailService2();
|
|
47161
47368
|
const ownerId3 = createHash29("sha256").update(identity.toLowerCase()).digest("hex").slice(0, 24);
|
|
47162
47369
|
const after = Math.floor(Date.parse(input.from) / 1e3);
|
|
@@ -61115,6 +61322,19 @@ async function checkHarvestLimits(user, reuseLockId) {
|
|
|
61115
61322
|
}
|
|
61116
61323
|
return null;
|
|
61117
61324
|
}
|
|
61325
|
+
app.post("/harvest/internal/resume/:id", async (c) => {
|
|
61326
|
+
const secret = c.req.header("authorization");
|
|
61327
|
+
if (!process.env.CRON_SECRET || secret !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
61328
|
+
return c.json({ error: "Unauthorized" }, 401);
|
|
61329
|
+
}
|
|
61330
|
+
const job = await getJob(c.req.param("id"));
|
|
61331
|
+
if (!job || job.options.executionOwner !== "direct" || job.options.serpOnly === true) {
|
|
61332
|
+
return c.json({ error: "PAA job not found" }, 404);
|
|
61333
|
+
}
|
|
61334
|
+
if (job.status !== "pending") return c.json({ job_id: job.id, status: job.status }, 409);
|
|
61335
|
+
scheduleDirectPaaHarvest(job.id);
|
|
61336
|
+
return c.json({ job_id: job.id, status: "pending", recovery_dispatched: true }, 202);
|
|
61337
|
+
});
|
|
61118
61338
|
app.post("/harvest", auth5, async (c) => {
|
|
61119
61339
|
const user = c.get("user");
|
|
61120
61340
|
const raw = await c.req.json().catch(() => ({}));
|
|
@@ -61198,6 +61418,7 @@ app.post("/harvest", auth5, async (c) => {
|
|
|
61198
61418
|
await createJobWithId(jobId2, user.id, options.query, {
|
|
61199
61419
|
...options,
|
|
61200
61420
|
executionOwner: "direct",
|
|
61421
|
+
paaRecoveryCount: 0,
|
|
61201
61422
|
billingHoldMc: harvestCost,
|
|
61202
61423
|
billingDebitKey,
|
|
61203
61424
|
...requestFingerprint3 ? { requestFingerprint: requestFingerprint3 } : {}
|
|
@@ -62737,7 +62958,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
62737
62958
|
return c.json({ error: "Unauthorized" }, 401);
|
|
62738
62959
|
}
|
|
62739
62960
|
const startedAt = Date.now();
|
|
62740
|
-
const { drainQueue } = await import("./worker-
|
|
62961
|
+
const { drainQueue } = await import("./worker-2BYACLNF.js");
|
|
62741
62962
|
const budget = { maxJobs: 10, deadlineMs: startedAt + CRON_TICK_DRAIN_BUDGET_MS };
|
|
62742
62963
|
const origin = `${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`;
|
|
62743
62964
|
const unfinished = [];
|
|
@@ -62775,10 +62996,12 @@ app.get("/cron/tick", async (c) => {
|
|
|
62775
62996
|
settleWithinTickBudget("siteExtractArtifactCleanup", unfinished, cleanupExpiredSiteExtractArtifacts(), { deleted: 0, store: "none" }),
|
|
62776
62997
|
settleWithinTickBudget("siteExtractRedispatch", unfinished, redispatchFundedSiteExtractJobs(10), { checked: 0, dispatched: 0, failed: 0 }),
|
|
62777
62998
|
settleWithinTickBudget("siteExtractReconcile", unfinished, reconcileSiteExtractSettlements(10), { checked: 0, settled: 0, failed: 0 }),
|
|
62778
|
-
settleWithinTickBudget("paaReconcile", unfinished, reconcilePaaHarvestSettlements(10), {
|
|
62999
|
+
settleWithinTickBudget("paaReconcile", unfinished, reconcilePaaHarvestSettlements(10, origin), {
|
|
62779
63000
|
checked: 0,
|
|
62780
63001
|
stalePartial: 0,
|
|
62781
63002
|
staleFailed: 0,
|
|
63003
|
+
requeued: 0,
|
|
63004
|
+
redispatched: 0,
|
|
62782
63005
|
settled: 0,
|
|
62783
63006
|
failed: 0,
|
|
62784
63007
|
providerChecked: 0,
|
|
@@ -62859,8 +63082,8 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
|
|
|
62859
63082
|
finishExtractJob: finishExtractJob2,
|
|
62860
63083
|
terminalExtractJobStatus: terminalExtractJobStatus2,
|
|
62861
63084
|
extractJobLimitInfo: extractJobLimitInfo2
|
|
62862
|
-
} = await import("./site-extract-repository-
|
|
62863
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
63085
|
+
} = await import("./site-extract-repository-XKSVXSSY.js");
|
|
63086
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-P2DTUVY3.js");
|
|
62864
63087
|
const existing = await getExtractJob2(jobId2);
|
|
62865
63088
|
if (!existing) return c.json({ error: "job not found" }, 404);
|
|
62866
63089
|
if (existing.status !== "failed") {
|
|
@@ -62887,7 +63110,7 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
|
|
|
62887
63110
|
if (!updated) return c.json({ error: "job state changed during re-finalization" }, 409);
|
|
62888
63111
|
let settlement = "already_settled_or_refunded";
|
|
62889
63112
|
if (job.billedMc == null && job.userId != null) {
|
|
62890
|
-
const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-
|
|
63113
|
+
const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-XKSVXSSY.js");
|
|
62891
63114
|
const heldMc = Number(job.options.heldMc ?? 0);
|
|
62892
63115
|
const successful = await countSuccessfulPages2(jobId2);
|
|
62893
63116
|
const usedMc = Math.min(successful * MC_COSTS.page_scrape, heldMc);
|