@canonry/canonry 7.76.0 → 7.76.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/{backfill-NG6PZM7X.js → backfill-REP7PTSI.js} +2 -2
- package/dist/{chunk-4ZXHTHUH.js → chunk-4MYZRVJ6.js} +8 -5
- package/dist/{chunk-2EXFCI5F.js → chunk-66BZEUOK.js} +2 -2
- package/dist/{chunk-BC56FPTQ.js → chunk-AQLTYL3Q.js} +1 -1
- package/dist/{chunk-M7OLPSCA.js → chunk-GDKMVOZI.js} +321 -251
- package/dist/{chunk-OF6UW77Y.js → chunk-HD2VVIPD.js} +1 -1
- package/dist/{chunk-AIC4FUOD.js → chunk-IAOPQ2VO.js} +14 -14
- package/dist/{chunk-DAOGINSR.js → chunk-KNERCHMI.js} +1 -1
- package/dist/{chunk-IZP4KKIJ.js → chunk-ST6FNS6A.js} +1 -1
- package/dist/{cli-commands-OZFEIIV6.js → cli-commands-JFKE3JZB.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{dashboard-P3DLDUTA.js → dashboard-3G4P32BY.js} +1 -1
- package/dist/{demo-FSRCJINC.js → demo-5CU3JDHC.js} +1 -1
- package/dist/{demo-server-ROGIRBAR.js → demo-server-43QV3UKM.js} +2 -2
- package/dist/index.d.ts +10 -10
- package/dist/index.js +5 -5
- package/dist/{init-V2W3KRGA.js → init-HUMX46OS.js} +1 -1
- package/dist/{intelligence-service-G6NCD4JJ.js → intelligence-service-NXZYQJBH.js} +2 -2
- package/dist/{serve-ZH36XF5Y.js → serve-CMWDXN5D.js} +6 -6
- package/dist/{session-QIN3JK6L.js → session-T3CLSPRC.js} +3 -3
- package/dist/{tools-POBUM7P7.js → tools-4CCRSYOR.js} +2 -2
- package/package.json +1 -1
|
@@ -3549,9 +3549,9 @@ function resolveOurPage(cq, inventory) {
|
|
|
3549
3549
|
if (cq.gscPage && cq.gscPosition !== null) {
|
|
3550
3550
|
return { url: cq.gscPage, position: cq.gscPosition, source: "gsc" };
|
|
3551
3551
|
}
|
|
3552
|
-
for (const
|
|
3553
|
-
if (slugMatchesQuery(
|
|
3554
|
-
return { url:
|
|
3552
|
+
for (const page2 of inventory) {
|
|
3553
|
+
if (slugMatchesQuery(page2.url, cq.query)) {
|
|
3554
|
+
return { url: page2.url, position: 100, source: "inventory" };
|
|
3555
3555
|
}
|
|
3556
3556
|
}
|
|
3557
3557
|
return null;
|
|
@@ -7392,16 +7392,16 @@ var SentimentService = class {
|
|
|
7392
7392
|
return { ...summary3, attemptCount: attemptCounts.get(row.id) ?? 0 };
|
|
7393
7393
|
}) };
|
|
7394
7394
|
}
|
|
7395
|
-
job(projectId, jobId,
|
|
7395
|
+
job(projectId, jobId, page2) {
|
|
7396
7396
|
const row = this.repository.getJob(projectId, jobId);
|
|
7397
7397
|
if (!row) throw notFound("Sentiment job", jobId);
|
|
7398
7398
|
const tally = this.jobTallies(projectId, [jobId], this.disabled(projectId)).get(jobId);
|
|
7399
7399
|
const scope = and9(eq15(sentimentJobItems.projectId, projectId), eq15(sentimentJobItems.jobId, jobId));
|
|
7400
|
-
if (!
|
|
7401
|
-
const limit = Math.max(1,
|
|
7400
|
+
if (!page2) return jobReceipt(row, tally, this.db.select({ attempt: sentimentAttempts }).from(sentimentAttempts).innerJoin(sentimentJobItems, jobAttemptJoin).where(scope).orderBy(sentimentAttempts.dispatchedAt, sentimentAttempts.id).all().map(({ attempt }) => attempt));
|
|
7401
|
+
const limit = Math.max(1, page2.limit ?? SENTIMENT_ATTEMPT_PAGE_DEFAULT);
|
|
7402
7402
|
let after = null;
|
|
7403
|
-
if (
|
|
7404
|
-
const token = this.verify(
|
|
7403
|
+
if (page2.cursor) {
|
|
7404
|
+
const token = this.verify(page2.cursor);
|
|
7405
7405
|
if (token.kind !== "attempt-page" || token.projectId !== projectId || token.jobId !== jobId) throw validationError("Attempt cursor does not match this sentiment job.");
|
|
7406
7406
|
after = token.after;
|
|
7407
7407
|
}
|
|
@@ -7532,9 +7532,9 @@ var SentimentService = class {
|
|
|
7532
7532
|
const ordered = [...groups.values()].sort(compareRows);
|
|
7533
7533
|
const start = rows.after ? ordered.findIndex((group) => compareRows(group, rows.after) > 0) : 0;
|
|
7534
7534
|
const from = start === -1 ? ordered.length : start;
|
|
7535
|
-
const
|
|
7535
|
+
const page2 = rows.limit === null ? ordered.slice(from) : ordered.slice(from, from + rows.limit);
|
|
7536
7536
|
const measuredBySourceSubject = new Map(items.map((item2) => [`${item2.work.snapshotId}\0${item2.member.subject.key}`, item2]));
|
|
7537
|
-
const queries2 =
|
|
7537
|
+
const queries2 = page2.map((group) => {
|
|
7538
7538
|
const key = queryRowKey(group);
|
|
7539
7539
|
const inRow = (edge) => queryRowKey(edge) === key;
|
|
7540
7540
|
const assessments = !rows.include.has("assessments") ? [] : group.eligible.map((member) => {
|
|
@@ -7567,7 +7567,7 @@ var SentimentService = class {
|
|
|
7567
7567
|
})();
|
|
7568
7568
|
return { ...scoreAssessments(group.measured, group.eligible, options), queryId: group.queryId, queryText: group.queryText, queryClass: selection.queryClass, sourceSnapshotIds: [...new Set(group.eligible.map((item2) => item2.snapshotId))].sort(), assessments, locations, executionNodeKey: group.executionNodeKey };
|
|
7569
7569
|
});
|
|
7570
|
-
const next = rows.limit !== null && from + rows.limit < ordered.length ? rowKey(
|
|
7570
|
+
const next = rows.limit !== null && from + rows.limit < ordered.length ? rowKey(page2.at(-1)) : null;
|
|
7571
7571
|
const criticizedProperties = selection.queryClass === "branded" && !disabled ? rankCriticizedProperties(breakdowns) : void 0;
|
|
7572
7572
|
return { summary: { ...base, breakdowns, ...criticizedProperties ? { criticizedProperties } : {} }, queries: queries2, total: ordered.length, next };
|
|
7573
7573
|
}
|
|
@@ -7648,8 +7648,8 @@ var SentimentService = class {
|
|
|
7648
7648
|
const state = this.present(read, settings, null).summary.state;
|
|
7649
7649
|
if (disabled) return { state, selection, items: [], nextCursor: null };
|
|
7650
7650
|
const items = read.items.filter((item2) => (!assessmentId || item2.work.id === assessmentId) && (!outcomes || outcomes.has(item2.outcome))).sort((a, b) => a.work.id.localeCompare(b.work.id)).filter((item2) => item2.work.id > after);
|
|
7651
|
-
const
|
|
7652
|
-
return { state, selection, items:
|
|
7651
|
+
const page2 = items.slice(0, limit);
|
|
7652
|
+
return { state, selection, items: page2.map((item2) => item2.evidence), nextCursor: items.length > limit ? this.sign({ projectId, selection, fingerprint: read.fingerprint, after: page2.at(-1).work.id }) : null };
|
|
7653
7653
|
}
|
|
7654
7654
|
previousRatedRun(projectId, query, toRunId) {
|
|
7655
7655
|
const target = this.db.select().from(runs).where(and9(eq15(runs.projectId, projectId), eq15(runs.id, toRunId))).get();
|
|
@@ -7910,6 +7910,130 @@ function createOutcomeEmitter(sink) {
|
|
|
7910
7910
|
// ../api-routes/src/oauth.ts
|
|
7911
7911
|
import crypto10 from "crypto";
|
|
7912
7912
|
import { and as and10, eq as eq16, inArray as inArray7, isNull as isNull2, lt as lt2 } from "drizzle-orm";
|
|
7913
|
+
|
|
7914
|
+
// ../api-routes/src/oauth-pages.ts
|
|
7915
|
+
var CANONRY_MARK = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="154.7 160.4 692.7 692.7" width="28" height="28">
|
|
7916
|
+
<rect x="154.7" y="160.4" width="692.7" height="692.7" rx="155" fill="#FFFFFF"/>
|
|
7917
|
+
<g fill="#000000">
|
|
7918
|
+
<path d="M643.280273,349.521912 C663.564758,358.227753 677.878296,372.354462 685.971619,392.573181 C686.972107,395.072723 688.558105,396.657318 690.965576,397.793091 C700.154480,402.128113 709.299805,406.557098 718.418152,411.038940 C720.137024,411.883789 722.297424,412.287781 723.082764,414.505646 C722.436829,416.736572 720.315369,417.297180 718.672974,418.283936 C710.677063,423.087982 702.737610,428.007751 694.536316,432.438995 C690.292847,434.731812 689.623474,437.601929 690.721252,441.873505 C694.409424,456.224579 697.080322,470.783447 698.648254,485.516296 C706.980408,563.808472 674.667969,637.691406 599.837036,675.696777 C591.244507,680.060791 589.348999,684.706055 588.762085,693.643799 C587.802551,708.253723 591.334656,719.604431 603.608582,728.042114 C606.993469,730.369080 609.692200,733.711975 612.633240,736.661011 C614.834778,738.868713 616.390259,741.451965 615.484070,744.714661 C614.463074,748.390442 611.040588,748.530701 608.186829,748.873535 C602.282593,749.582764 596.495117,748.300415 591.085144,746.121216 C584.405823,743.430725 578.196350,743.029907 571.347473,745.981567 C565.596313,748.460205 559.291748,749.906616 552.809509,748.608948 C546.415894,747.329041 544.679260,742.387268 549.100769,737.268677 C553.124512,732.610596 557.478271,728.232239 561.777283,723.819031 C565.233093,720.271423 566.768433,716.091919 566.706421,711.171570 C566.618774,704.216675 566.684204,697.259827 566.684204,689.673462 C558.493774,691.342041 551.083862,693.058167 543.598328,694.328552 C532.268250,696.251221 520.852844,697.742981 509.332672,697.280762 C504.396545,697.082764 503.395782,699.117798 502.988739,703.669495 C502.131439,713.256897 504.788086,720.890442 512.407776,726.972046 C516.164429,729.970459 519.393433,733.638672 522.797852,737.066711 C525.003601,739.287781 526.529358,741.943420 525.592102,745.147461 C524.603699,748.526367 521.390869,748.625854 518.629883,748.986389 C512.858459,749.740051 507.260590,748.525085 502.034332,746.295715 C496.310394,743.854187 491.006897,743.716125 485.176880,746.123047 C479.977631,748.269592 474.388336,749.726379 468.595459,748.899902 C462.113007,747.975098 460.216949,743.495361 464.340210,738.341492 C467.662201,734.189087 471.266022,730.214600 475.101440,726.532776 C479.828003,721.995667 481.496887,716.581360 481.076111,710.263123 C480.976654,708.769592 481.041229,707.264771 481.039337,705.765137 C481.027771,696.497192 481.037323,696.410034 471.694427,695.478516 C442.248657,692.542664 414.247101,684.167725 387.215302,672.526550 C348.882019,656.018433 314.611755,633.294312 284.843445,603.941284 C282.757477,601.884460 280.240143,600.093811 279.139984,596.988037 C281.286224,594.889709 283.922913,595.734070 286.249481,595.797302 C308.058136,596.389587 329.499695,594.198181 350.292328,587.321228 C397.447968,571.724976 433.482452,542.002075 460.186523,500.492340 C473.036499,480.517883 482.051941,458.583374 492.496124,437.377869 C503.334290,415.372559 514.369690,393.433014 532.379700,376.153564 C552.092468,357.240356 575.247620,345.211548 602.822083,343.025940 C616.616638,341.932617 630.063782,344.054810 643.280273,349.521912 M495.527954,631.939941 C547.588440,610.400635 576.816711,571.974487 581.564331,515.495239 C581.785034,512.869202 582.262817,510.040649 580.342407,507.036652 C576.384949,514.126831 573.027527,520.802063 568.784912,526.969849 C554.886353,547.175476 536.622559,562.492676 515.187866,573.967163 C493.818420,585.406677 473.139191,597.697327 455.509399,614.599426 C445.589752,624.109680 434.727051,632.323120 421.726410,637.308838 C420.815826,637.658081 419.832977,638.096313 420.111389,640.036011 C445.648468,644.186218 470.547882,641.495972 495.527954,631.939941 M620.682800,404.632080 C621.568542,406.034393 622.304260,407.563599 623.365356,408.817505 C628.476868,414.857666 636.107910,416.365417 643.242798,412.856628 C649.758179,409.652466 653.593445,402.235199 652.212341,395.509857 C650.181763,385.621887 641.324646,379.919281 631.735962,382.326355 C622.488525,384.647736 617.546265,394.065552 620.682800,404.632080 z"/>
|
|
7919
|
+
<path d="M609.415771,298.999939 C609.404480,308.826233 609.236938,318.156067 609.453552,327.476990 C609.549316,331.600281 608.532349,333.592590 603.946533,333.514648 C599.994507,333.447479 595.979919,334.127533 592.078735,334.906799 C588.809875,335.559723 586.920410,334.955017 585.414673,331.663605 C576.860962,312.965210 563.870667,298.161072 545.954712,287.865753 C542.771973,286.036835 540.935547,284.239990 545.001099,281.431763 C562.686279,269.215973 582.051392,262.950745 603.739685,264.480255 C607.911316,264.774414 609.185059,266.794464 609.195984,270.523499 C609.223389,279.849091 609.336914,289.174438 609.415771,298.999939 z"/>
|
|
7920
|
+
<path d="M528.548218,295.440735 C530.920166,292.833984 533.166809,292.846558 535.939697,294.247742 C553.777527,303.261475 567.022461,316.798035 576.192078,334.477356 C577.604675,337.200958 577.081482,338.818573 574.231934,339.850098 C565.409119,343.044037 557.316101,347.609619 549.694580,353.041199 C548.369812,353.985291 547.054626,354.269806 545.502991,353.559906 C532.158264,347.454254 518.989014,348.832764 505.922913,354.526489 C505.487671,354.716187 504.953705,354.679352 504.485840,354.745270 C498.829224,345.102753 512.282654,311.787689 528.548218,295.440735 z"/>
|
|
7921
|
+
<path d="M627.180786,334.941315 C618.853943,333.440460 618.957336,333.440582 618.967651,325.463226 C618.989685,308.494110 618.886902,291.524811 618.848572,274.555603 C618.835571,268.806610 619.716431,268.037811 625.258728,269.238525 C643.614075,273.215179 658.819092,282.436798 671.065857,296.672333 C673.732483,299.771912 674.003357,301.755615 670.442383,304.695953 C660.370789,313.012299 655.150024,324.168915 653.311096,336.971527 C652.435242,343.069092 652.024658,343.353271 646.585510,340.962372 C640.477112,338.277283 634.187866,336.164337 627.180786,334.941315 z"/>
|
|
7922
|
+
</g>
|
|
7923
|
+
</svg>`;
|
|
7924
|
+
var FONT_PATH = /^\/[\w\-./]*\.woff2$/;
|
|
7925
|
+
var styles = `
|
|
7926
|
+
:root {
|
|
7927
|
+
color-scheme: dark;
|
|
7928
|
+
--bg: hsl(0 0% 4%); --surface: hsl(0 0% 4%); --hover: hsl(0 0% 10%);
|
|
7929
|
+
--border: hsl(0 0% 18%); --border-strong: hsl(0 0% 53%);
|
|
7930
|
+
--text: hsl(0 0% 93%); --secondary: hsl(0 0% 63%);
|
|
7931
|
+
--accent-hover: hsl(0 0% 80%); --focus: hsl(210 100% 66%);
|
|
7932
|
+
--negative: hsl(358 100% 69%);
|
|
7933
|
+
--caution: hsl(39 90% 50%); --caution-surface: hsl(35 100% 8%); --caution-border: hsl(35 100% 17%);
|
|
7934
|
+
font-family: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
7935
|
+
font-synthesis: none; -webkit-font-smoothing: antialiased;
|
|
7936
|
+
background: var(--bg); color: var(--text);
|
|
7937
|
+
}
|
|
7938
|
+
* { box-sizing: border-box; }
|
|
7939
|
+
body { margin: 0; font-size: 14px; line-height: 20px; }
|
|
7940
|
+
main { min-height: 100vh; min-height: 100svh; display: flex; align-items: center; justify-content: center; padding: 48px 24px; }
|
|
7941
|
+
.gate { width: 100%; max-width: 448px; min-width: 0; }
|
|
7942
|
+
.brand { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 24px; font-size: 18px; line-height: 24px; font-weight: 600; }
|
|
7943
|
+
.brand-icon, .brand-icon svg { display: block; width: 28px; height: 28px; }
|
|
7944
|
+
.panel { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 32px; }
|
|
7945
|
+
h1 { margin: 0; font-size: 24px; line-height: 32px; font-weight: 600; letter-spacing: -.96px; }
|
|
7946
|
+
p { margin: 0; overflow-wrap: anywhere; }
|
|
7947
|
+
.intro { color: var(--secondary); margin-top: 8px; }
|
|
7948
|
+
strong { color: var(--text); font-weight: 550; }
|
|
7949
|
+
.err { margin-top: 16px; color: var(--negative); }
|
|
7950
|
+
.warn { margin-top: 16px; padding: 12px; border: 1px solid var(--caution-border); border-radius: 6px; background: var(--caution-surface); color: var(--caution); font-size: 13px; line-height: 20px; }
|
|
7951
|
+
.grant { margin: 24px 0 0; padding: 16px 0 20px; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); font-size: 13px; line-height: 20px; }
|
|
7952
|
+
dt { color: var(--secondary); }
|
|
7953
|
+
dd { margin: 4px 0 0; overflow-wrap: anywhere; }
|
|
7954
|
+
dd + dt { margin-top: 12px; }
|
|
7955
|
+
form { margin-top: 28px; }
|
|
7956
|
+
.grant + form, .warn + form { margin-top: 0; }
|
|
7957
|
+
label { display: block; margin-bottom: 8px; font-weight: 500; }
|
|
7958
|
+
.field + .field { margin-top: 16px; }
|
|
7959
|
+
input, button { font: inherit; }
|
|
7960
|
+
input:is([type="text"], [type="password"]) { display: block; width: 100%; min-width: 0; height: 40px; padding: 0 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); color: var(--text); }
|
|
7961
|
+
input:is([type="text"], [type="password"]):hover { border-color: var(--border-strong); }
|
|
7962
|
+
.actions { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; margin-top: 24px; }
|
|
7963
|
+
.actions.single { grid-template-columns: minmax(0, 1fr); }
|
|
7964
|
+
button { min-height: 36px; border: 1px solid transparent; border-radius: 6px; padding: 7px 14px; font-size: 14px; line-height: 20px; font-weight: 500; cursor: pointer; transition: background-color 150ms ease-out, border-color 150ms ease-out; }
|
|
7965
|
+
.primary { background: var(--text); color: var(--bg); }
|
|
7966
|
+
.primary:hover { background: var(--accent-hover); }
|
|
7967
|
+
.primary:active { background: var(--secondary); }
|
|
7968
|
+
.secondary { border-color: var(--border); background: var(--surface); color: var(--text); }
|
|
7969
|
+
.secondary:hover { background: var(--hover); border-color: var(--border-strong); }
|
|
7970
|
+
.secondary:active { background: var(--border); }
|
|
7971
|
+
:where(input, button):focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
|
|
7972
|
+
@media (max-width: 480px) {
|
|
7973
|
+
main { padding: 32px 16px; align-items: flex-start; }
|
|
7974
|
+
.panel { padding: 24px; }
|
|
7975
|
+
.actions { grid-template-columns: minmax(0, 1fr); }
|
|
7976
|
+
input:is([type="text"], [type="password"]) { height: 48px; font-size: 16px; }
|
|
7977
|
+
button { min-height: 44px; padding: 11px 14px; }
|
|
7978
|
+
}
|
|
7979
|
+
@media (pointer: coarse) { input:is([type="text"], [type="password"]), button { min-height: 44px; } }
|
|
7980
|
+
@media (prefers-reduced-motion: reduce) { button { transition: none; } }
|
|
7981
|
+
@media (forced-colors: active) { .primary, .secondary, input:is([type="text"], [type="password"]) { border: 1px solid ButtonText; } }
|
|
7982
|
+
`;
|
|
7983
|
+
function escapeHtml(value) {
|
|
7984
|
+
return value.replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[char] ?? char);
|
|
7985
|
+
}
|
|
7986
|
+
function breakableUrl(value) {
|
|
7987
|
+
return escapeHtml(value).replace(/(?<!\/)\/(?!\/)/g, "/<wbr>");
|
|
7988
|
+
}
|
|
7989
|
+
function fontFace(fontUrl) {
|
|
7990
|
+
if (!fontUrl || !FONT_PATH.test(fontUrl)) return "";
|
|
7991
|
+
return `@font-face {
|
|
7992
|
+
font-family: 'Geist'; font-style: normal; font-weight: 100 900; font-display: swap;
|
|
7993
|
+
src: url('${fontUrl}') format('woff2');
|
|
7994
|
+
}`;
|
|
7995
|
+
}
|
|
7996
|
+
function gatePage(title, body, fontUrl) {
|
|
7997
|
+
return `<!doctype html>
|
|
7998
|
+
<html lang="en"><head>
|
|
7999
|
+
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8000
|
+
<meta name="color-scheme" content="dark"><meta name="theme-color" content="#0a0a0a">
|
|
8001
|
+
<title>${title} \xB7 Canonry</title>
|
|
8002
|
+
<style>${fontFace(fontUrl)}${styles}</style>
|
|
8003
|
+
</head><body><main><div class="gate">
|
|
8004
|
+
<div class="brand"><span class="brand-icon" aria-hidden="true">${CANONRY_MARK}</span><span>Canonry</span></div>
|
|
8005
|
+
<section class="panel" aria-labelledby="gate-title">
|
|
8006
|
+
${body}
|
|
8007
|
+
</section>
|
|
8008
|
+
</div></main></body></html>`;
|
|
8009
|
+
}
|
|
8010
|
+
function renderSignInPage(o) {
|
|
8011
|
+
return gatePage("Sign in", `<h1 id="gate-title">Sign in to continue</h1>
|
|
8012
|
+
${o.error ? `<p class="err" role="alert">${escapeHtml(o.error)}</p>` : ""}
|
|
8013
|
+
<form method="post" action="${escapeHtml(o.action)}">
|
|
8014
|
+
<div class="field"><label for="name">Name</label><input id="name" type="text" name="name" autocomplete="username" autocapitalize="none" spellcheck="false" autofocus></div>
|
|
8015
|
+
<div class="field"><label for="password">Password</label><input id="password" type="password" name="password" autocomplete="current-password"></div>
|
|
8016
|
+
<div class="actions single"><button class="primary" type="submit">Sign in</button></div>
|
|
8017
|
+
</form>`, o.fontUrl);
|
|
8018
|
+
}
|
|
8019
|
+
function renderConsentPage(o) {
|
|
8020
|
+
const cut = o.action.indexOf("?");
|
|
8021
|
+
const consentAction = cut === -1 ? `${o.action}/consent` : `${o.action.slice(0, cut)}/consent${o.action.slice(cut)}`;
|
|
8022
|
+
return gatePage("Allow access", `<h1 id="gate-title">Allow access?</h1>
|
|
8023
|
+
<p class="intro"><strong>${escapeHtml(o.clientName)}</strong> wants to access Canonry as <strong>${escapeHtml(o.userName)}</strong>.</p>
|
|
8024
|
+
${o.selfRegistered ? '<p class="warn">This application chose its own name and has not been verified by anyone. Check the address below before allowing it.</p>' : ""}
|
|
8025
|
+
<dl class="grant">
|
|
8026
|
+
<dt>Permissions</dt><dd>${escapeHtml(o.scope)}</dd>
|
|
8027
|
+
<dt>Redirects to</dt><dd>${breakableUrl(o.redirectUri)}</dd>
|
|
8028
|
+
</dl>
|
|
8029
|
+
${o.scope.split(/\s+/).includes(RESEARCH_RUN_SCOPE) ? `<p class="warn">Run research queries using the operator's provider quota, subject to the shared daily research limit. This does not grant permission to change tracking or settings.</p>` : ""}
|
|
8030
|
+
<form method="post" action="${escapeHtml(consentAction)}">
|
|
8031
|
+
<input type="hidden" name="csrf" value="${escapeHtml(o.csrf)}">
|
|
8032
|
+
<div class="actions"><button class="primary" type="submit" name="approve" value="yes">Allow</button><button class="secondary" type="submit" name="approve" value="no">Deny</button></div>
|
|
8033
|
+
</form>`, o.fontUrl);
|
|
8034
|
+
}
|
|
8035
|
+
|
|
8036
|
+
// ../api-routes/src/oauth.ts
|
|
7913
8037
|
var CODE_TTL_MS = 6e4;
|
|
7914
8038
|
var ACCESS_TTL_MS = 60 * 60 * 1e3;
|
|
7915
8039
|
var REFRESH_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -7959,66 +8083,11 @@ function resolveRequestedScope(requested) {
|
|
|
7959
8083
|
function badRequest(reply, error, description) {
|
|
7960
8084
|
return reply.status(400).send({ error, error_description: description });
|
|
7961
8085
|
}
|
|
7962
|
-
function escapeHtml(value) {
|
|
7963
|
-
return value.replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[char] ?? char);
|
|
7964
|
-
}
|
|
7965
|
-
function signInPage(action, error) {
|
|
7966
|
-
return page(`<h1>Sign in to continue</h1>
|
|
7967
|
-
${error ? `<p class="err">${escapeHtml(error)}</p>` : ""}
|
|
7968
|
-
<label for="name">Name</label><input id="name" name="name" autocomplete="username" autofocus>
|
|
7969
|
-
<label for="password">Password</label><input id="password" name="password" type="password" autocomplete="current-password">
|
|
7970
|
-
<button type="submit">Sign in</button>`, action);
|
|
7971
|
-
}
|
|
7972
|
-
function consentPage(o) {
|
|
7973
|
-
const cut = o.action.indexOf("?");
|
|
7974
|
-
const consentAction = cut === -1 ? `${o.action}/consent` : `${o.action.slice(0, cut)}/consent${o.action.slice(cut)}`;
|
|
7975
|
-
return page(`<h1>Allow access?</h1>
|
|
7976
|
-
<p class="who"><strong>${escapeHtml(o.clientName)}</strong> wants to access Canonry as
|
|
7977
|
-
<strong>${escapeHtml(o.userName)}</strong>.</p>
|
|
7978
|
-
${o.selfRegistered ? `<p class="warn">This application chose its own name and has not been verified by anyone.
|
|
7979
|
-
Check the address below before allowing it.</p>` : ""}
|
|
7980
|
-
<dl>
|
|
7981
|
-
<dt>Permissions</dt><dd>${escapeHtml(o.scope)}</dd>
|
|
7982
|
-
<dt>Redirects to</dt><dd class="uri">${escapeHtml(o.redirectUri)}</dd>
|
|
7983
|
-
</dl>
|
|
7984
|
-
${o.scope.split(/\s+/).includes(RESEARCH_RUN_SCOPE) ? `<p class="warn">Run research queries using the operator's provider quota, subject to the shared daily research limit. This does not grant permission to change tracking or settings.</p>` : ""}
|
|
7985
|
-
<input type="hidden" name="csrf" value="${escapeHtml(o.csrf)}">
|
|
7986
|
-
<div class="row">
|
|
7987
|
-
<button type="submit" name="approve" value="no" class="ghost">Deny</button>
|
|
7988
|
-
<button type="submit" name="approve" value="yes">Allow</button>
|
|
7989
|
-
</div>`, consentAction);
|
|
7990
|
-
}
|
|
7991
8086
|
function sendGatePage(reply, html) {
|
|
7992
8087
|
return reply.header(
|
|
7993
8088
|
"content-security-policy",
|
|
7994
|
-
"frame-ancestors 'none'; default-src 'none'; style-src 'unsafe-inline'; form-action 'self'"
|
|
7995
|
-
).header("x-frame-options", "DENY").header("referrer-policy", "
|
|
7996
|
-
}
|
|
7997
|
-
function page(inner, action) {
|
|
7998
|
-
return `<!doctype html>
|
|
7999
|
-
<html lang="en"><head><meta charset="utf-8">
|
|
8000
|
-
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
8001
|
-
<title>Canonry</title>
|
|
8002
|
-
<style>
|
|
8003
|
-
body{font:16px/1.5 system-ui,sans-serif;background:#10141c;color:#e8eaed;display:grid;place-items:center;min-height:100vh;margin:0}
|
|
8004
|
-
form{background:#171c26;padding:2rem;border-radius:12px;width:min(26rem,90vw);display:grid;gap:.75rem}
|
|
8005
|
-
h1{font-size:1.1rem;margin:0 0 .5rem}
|
|
8006
|
-
label,dt{font-size:.85rem;color:#9aa4b2}
|
|
8007
|
-
dl{margin:0;display:grid;gap:.5rem}
|
|
8008
|
-
dd{margin:0}
|
|
8009
|
-
.uri{word-break:break-all;font-family:ui-monospace,monospace;font-size:.85rem}
|
|
8010
|
-
input{padding:.6rem;border-radius:6px;border:1px solid #2a3140;background:#0d1117;color:inherit;font:inherit}
|
|
8011
|
-
input[type=hidden]{display:none}
|
|
8012
|
-
button{padding:.6rem 1rem;border-radius:6px;border:0;background:#3b82f6;color:#fff;font:inherit;cursor:pointer}
|
|
8013
|
-
.ghost{background:#2a3140}
|
|
8014
|
-
.row{display:flex;gap:.5rem;justify-content:flex-end}
|
|
8015
|
-
.err{color:#f87171;font-size:.85rem}
|
|
8016
|
-
.who{margin:0}
|
|
8017
|
-
.warn{margin:0;padding:.6rem;border-radius:6px;background:#3a2a12;color:#fbbf24;font-size:.85rem}
|
|
8018
|
-
</style></head>
|
|
8019
|
-
<body><form method="post" action="${escapeHtml(action)}">
|
|
8020
|
-
${inner}
|
|
8021
|
-
</form></body></html>`;
|
|
8089
|
+
"frame-ancestors 'none'; default-src 'none'; style-src 'unsafe-inline'; font-src 'self'; form-action 'self'"
|
|
8090
|
+
).header("x-frame-options", "DENY").header("referrer-policy", "same-origin").header("cache-control", "no-store").type("text/html").send(html);
|
|
8022
8091
|
}
|
|
8023
8092
|
var CONSENT_SECRET = crypto10.randomBytes(32);
|
|
8024
8093
|
function registerOAuthRoutes(app, opts) {
|
|
@@ -8116,16 +8185,17 @@ function registerOAuthRoutesIn(app, opts) {
|
|
|
8116
8185
|
}
|
|
8117
8186
|
const user = opts.resolveUser(request, reply);
|
|
8118
8187
|
if (!user) {
|
|
8119
|
-
return sendGatePage(reply,
|
|
8188
|
+
return sendGatePage(reply, renderSignInPage({ action: request.url, error: null, fontUrl: opts.fontUrl }));
|
|
8120
8189
|
}
|
|
8121
|
-
return sendGatePage(reply,
|
|
8190
|
+
return sendGatePage(reply, renderConsentPage({
|
|
8122
8191
|
action: request.url,
|
|
8123
8192
|
clientName: client.name,
|
|
8124
8193
|
selfRegistered: client.registration === "dynamic",
|
|
8125
8194
|
redirectUri,
|
|
8126
8195
|
scope: grantedScope,
|
|
8127
8196
|
userName: user.name,
|
|
8128
|
-
csrf: consentToken(user.id, clientId, redirectUri, grantedScope)
|
|
8197
|
+
csrf: consentToken(user.id, clientId, redirectUri, grantedScope),
|
|
8198
|
+
fontUrl: opts.fontUrl
|
|
8129
8199
|
}));
|
|
8130
8200
|
});
|
|
8131
8201
|
app.post(`${authorizationPath}/consent`, async (request, reply) => {
|
|
@@ -8244,11 +8314,11 @@ function registerOAuthRoutesIn(app, opts) {
|
|
|
8244
8314
|
const name = body.name?.trim();
|
|
8245
8315
|
const password = body.password;
|
|
8246
8316
|
if (!name || !password) {
|
|
8247
|
-
return sendGatePage(reply,
|
|
8317
|
+
return sendGatePage(reply, renderSignInPage({ action: request.url, error: "Enter a name and password.", fontUrl: opts.fontUrl }));
|
|
8248
8318
|
}
|
|
8249
8319
|
const result = await opts.credentials.verify(request, name, password);
|
|
8250
8320
|
if (!result.ok) {
|
|
8251
|
-
return sendGatePage(reply,
|
|
8321
|
+
return sendGatePage(reply, renderSignInPage({ action: request.url, error: result.message, fontUrl: opts.fontUrl }));
|
|
8252
8322
|
}
|
|
8253
8323
|
void reply.header("set-cookie", opts.startSession(result.user.id));
|
|
8254
8324
|
return reply.redirect(request.url);
|
|
@@ -13552,7 +13622,7 @@ function runProgress(db, displayed, plan) {
|
|
|
13552
13622
|
}
|
|
13553
13623
|
function planV1Overview(db, projectId, active, query, scope) {
|
|
13554
13624
|
const displayed = selectDisplayedRun(db, projectId, active, query);
|
|
13555
|
-
const { page:
|
|
13625
|
+
const { page: page2, outcomes } = pageOf(
|
|
13556
13626
|
propertyLabels(active.plan, scope).filter((row) => matchesSearch(row, query.search)).map((row) => ({
|
|
13557
13627
|
...row,
|
|
13558
13628
|
mentionCoverage: unavailable2("plan_v1"),
|
|
@@ -13585,7 +13655,7 @@ function planV1Overview(db, projectId, active, query, scope) {
|
|
|
13585
13655
|
brandPresence: unavailable2("plan_v1"),
|
|
13586
13656
|
sov: unavailable2("plan_v1")
|
|
13587
13657
|
},
|
|
13588
|
-
properties:
|
|
13658
|
+
properties: page2,
|
|
13589
13659
|
outcomes,
|
|
13590
13660
|
flags: { total: 0 }
|
|
13591
13661
|
};
|
|
@@ -13597,7 +13667,7 @@ function planV2Overview(db, projectId, active, plan, query, scope, cache2) {
|
|
|
13597
13667
|
const currentDto = current ? { currentRunId: current.id } : {};
|
|
13598
13668
|
const locate = propertyLocations(plan);
|
|
13599
13669
|
if (!displayed) {
|
|
13600
|
-
const { page:
|
|
13670
|
+
const { page: page3, outcomes: outcomes2 } = pageOf(
|
|
13601
13671
|
propertyLabels(plan, scope).filter((row) => matchesSearch(row, query.search)).map((row) => ({
|
|
13602
13672
|
...row,
|
|
13603
13673
|
...metroFields(locate(row.targetKey)),
|
|
@@ -13629,7 +13699,7 @@ function planV2Overview(db, projectId, active, plan, query, scope, cache2) {
|
|
|
13629
13699
|
brandPresence: unavailable2("no_completed_run"),
|
|
13630
13700
|
sov: unavailable2("no_completed_run")
|
|
13631
13701
|
},
|
|
13632
|
-
properties:
|
|
13702
|
+
properties: page3,
|
|
13633
13703
|
outcomes: outcomes2,
|
|
13634
13704
|
flags: { total: 0 }
|
|
13635
13705
|
};
|
|
@@ -13659,7 +13729,7 @@ function planV2Overview(db, projectId, active, plan, query, scope, cache2) {
|
|
|
13659
13729
|
const measured = new Map(
|
|
13660
13730
|
overview.properties.map((row) => [row.targetId, row])
|
|
13661
13731
|
);
|
|
13662
|
-
const { page:
|
|
13732
|
+
const { page: page2, outcomes } = pageOf(
|
|
13663
13733
|
propertyLabels(plan, scope).filter((row) => matchesSearch(row, query.search)).map((row) => {
|
|
13664
13734
|
const property = measured.get(row.targetKey);
|
|
13665
13735
|
return {
|
|
@@ -13713,7 +13783,7 @@ function planV2Overview(db, projectId, active, plan, query, scope, cache2) {
|
|
|
13713
13783
|
// the browser migrates off it (§0.2). The two must never diverge.
|
|
13714
13784
|
sov: brandPresence
|
|
13715
13785
|
},
|
|
13716
|
-
properties:
|
|
13786
|
+
properties: page2,
|
|
13717
13787
|
outcomes,
|
|
13718
13788
|
flags: { total: overview.flags },
|
|
13719
13789
|
...namedShareOfVoice === void 0 ? {} : { namedShareOfVoice }
|
|
@@ -22789,7 +22859,7 @@ function compactPortfolioPage(response, query, versionId, evidence, cursor) {
|
|
|
22789
22859
|
})).toString("base64url") : null
|
|
22790
22860
|
};
|
|
22791
22861
|
};
|
|
22792
|
-
const fits = (
|
|
22862
|
+
const fits = (page3) => JSON.stringify(page3, null, 2).length <= 18e3;
|
|
22793
22863
|
const initialComplete = build(requested, initialSummaryLimit);
|
|
22794
22864
|
if (fits(initialComplete)) return measurementPortfolioSummaryResponseSchema.parse(initialComplete);
|
|
22795
22865
|
const minimum = Math.min(1, requested);
|
|
@@ -22805,19 +22875,19 @@ function compactPortfolioPage(response, query, versionId, evidence, cursor) {
|
|
|
22805
22875
|
}
|
|
22806
22876
|
const complete = build(requested, summaryLimit);
|
|
22807
22877
|
if (fits(complete)) return measurementPortfolioSummaryResponseSchema.parse(complete);
|
|
22808
|
-
let
|
|
22809
|
-
if (!fits(
|
|
22878
|
+
let page2 = build(minimum, summaryLimit);
|
|
22879
|
+
if (!fits(page2)) throw validationError("One portfolio row or its metadata exceeds the compact page budget. Read a narrower scope without compact=true.");
|
|
22810
22880
|
let low = minimum + 1;
|
|
22811
22881
|
let high = requested;
|
|
22812
22882
|
while (low <= high) {
|
|
22813
22883
|
const count10 = Math.floor((low + high) / 2);
|
|
22814
22884
|
const candidate = build(count10, summaryLimit);
|
|
22815
22885
|
if (fits(candidate)) {
|
|
22816
|
-
|
|
22886
|
+
page2 = candidate;
|
|
22817
22887
|
low = count10 + 1;
|
|
22818
22888
|
} else high = count10 - 1;
|
|
22819
22889
|
}
|
|
22820
|
-
return measurementPortfolioSummaryResponseSchema.parse(
|
|
22890
|
+
return measurementPortfolioSummaryResponseSchema.parse(page2);
|
|
22821
22891
|
}
|
|
22822
22892
|
function portfolioAnswerEvidence(plan, materialized, filters, targetKeys) {
|
|
22823
22893
|
const targets = new Set(targetKeys);
|
|
@@ -24036,7 +24106,7 @@ function parseCursor3(value) {
|
|
|
24036
24106
|
return null;
|
|
24037
24107
|
}
|
|
24038
24108
|
}
|
|
24039
|
-
function
|
|
24109
|
+
function page(rows, keyOf, kind, queryClass, input, run) {
|
|
24040
24110
|
const selectionFingerprint = fingerprint({
|
|
24041
24111
|
mode: input.mode,
|
|
24042
24112
|
activeRevision: input.activeRevision,
|
|
@@ -24176,8 +24246,8 @@ function emptyPopulation(queryClass, definition2, input) {
|
|
|
24176
24246
|
queryClass,
|
|
24177
24247
|
summary: summary2(candidates, definition2, populationTargetKeys),
|
|
24178
24248
|
trend: [],
|
|
24179
|
-
queries:
|
|
24180
|
-
evidence:
|
|
24249
|
+
queries: page([], () => "", "queries", queryClass, input, void 0),
|
|
24250
|
+
evidence: page([], () => "", "evidence", queryClass, input, void 0),
|
|
24181
24251
|
competitorAvailability: definition2.competitorAvailability,
|
|
24182
24252
|
competitors: [],
|
|
24183
24253
|
observedCompetitors: [],
|
|
@@ -24235,8 +24305,8 @@ function buildVisibilityReport(input) {
|
|
|
24235
24305
|
summary: selectedSummary,
|
|
24236
24306
|
trend,
|
|
24237
24307
|
...basis === void 0 ? {} : { comparison: populationComparison(basis, selectedSummary, input.selection, queryClass) },
|
|
24238
|
-
queries:
|
|
24239
|
-
evidence:
|
|
24308
|
+
queries: page(rows, (row) => [row.queryKey, row.provider, row.model ?? "", row.location ?? ""].join("\0"), "queries", queryClass, input, selectedRun),
|
|
24309
|
+
evidence: page(evidence, (row) => [row.answerId, row.runId].join("\0"), "evidence", queryClass, input, selectedRun),
|
|
24240
24310
|
competitorAvailability: definition2.competitorAvailability,
|
|
24241
24311
|
competitors: competitorRows(selected),
|
|
24242
24312
|
observedCompetitors: observedCompetitorRows(selected),
|
|
@@ -29858,9 +29928,9 @@ async function journeyRoutes(app) {
|
|
|
29858
29928
|
const visitor = app.db.select().from(journeyVisitors).where(and42(eq50(journeyVisitors.projectId, project.id), eq50(journeyVisitors.visitorKey, request.params.visitorKey))).get();
|
|
29859
29929
|
if (!visitor) throw notFound("Journey", request.params.visitorKey);
|
|
29860
29930
|
const visits = visitsByVisitor(app.db, project.id, [visitor.visitorKey]).get(visitor.visitorKey) ?? [];
|
|
29861
|
-
const
|
|
29931
|
+
const page2 = visits.slice(offset, offset + limit);
|
|
29862
29932
|
const events = /* @__PURE__ */ new Map();
|
|
29863
|
-
for (const part of chunks(
|
|
29933
|
+
for (const part of chunks(page2.map((v) => v.id))) {
|
|
29864
29934
|
for (const row of app.db.select().from(journeyEvents).where(inArray28(journeyEvents.visitId, part)).orderBy(asc10(journeyEvents.ts)).all()) {
|
|
29865
29935
|
const list = events.get(row.visitId);
|
|
29866
29936
|
if (list) list.push(row);
|
|
@@ -29873,7 +29943,7 @@ async function journeyRoutes(app) {
|
|
|
29873
29943
|
totalVisits: visits.length,
|
|
29874
29944
|
limit,
|
|
29875
29945
|
offset,
|
|
29876
|
-
visits:
|
|
29946
|
+
visits: page2.map((v) => ({
|
|
29877
29947
|
...visitDto(v),
|
|
29878
29948
|
events: (events.get(v.id) ?? []).map((e) => ({ ts: e.ts, method: e.method, path: e.path, status: e.status, kind: e.kind === "data" ? "data" : "page", aiTouch: e.aiTouch }))
|
|
29879
29949
|
}))
|
|
@@ -31190,9 +31260,9 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
31190
31260
|
return created;
|
|
31191
31261
|
};
|
|
31192
31262
|
for (const row of pageSearchRows) {
|
|
31193
|
-
const
|
|
31194
|
-
|
|
31195
|
-
|
|
31263
|
+
const page2 = ensurePage(row.page);
|
|
31264
|
+
page2.gsc.clicks += row.clicks;
|
|
31265
|
+
page2.gsc.impressions += row.impressions;
|
|
31196
31266
|
}
|
|
31197
31267
|
if (nativeAcquisition.status === "never-synced") for (const row of gaWindow) {
|
|
31198
31268
|
ensurePage(row.landingPageNormalized ?? row.landingPage).ga4OrganicSessions += row.organicSessions;
|
|
@@ -33549,12 +33619,12 @@ function aggregateGscByQuery(rows, queryTotals = []) {
|
|
|
33549
33619
|
const accurateByQuery = new Map(queryTotals.map((t) => [t.query, t]));
|
|
33550
33620
|
const accumulators = /* @__PURE__ */ new Map();
|
|
33551
33621
|
for (const r of rows) {
|
|
33552
|
-
const
|
|
33622
|
+
const page2 = extractPath2(r.page);
|
|
33553
33623
|
const position = Number(r.position) || 0;
|
|
33554
33624
|
const existing = accumulators.get(r.query);
|
|
33555
33625
|
if (!existing) {
|
|
33556
33626
|
accumulators.set(r.query, {
|
|
33557
|
-
bestPage:
|
|
33627
|
+
bestPage: page2,
|
|
33558
33628
|
bestPageImpressions: r.impressions,
|
|
33559
33629
|
totalClicks: r.clicks,
|
|
33560
33630
|
totalImpressions: r.impressions,
|
|
@@ -33566,7 +33636,7 @@ function aggregateGscByQuery(rows, queryTotals = []) {
|
|
|
33566
33636
|
existing.totalImpressions += r.impressions;
|
|
33567
33637
|
existing.weightedPositionSum += position * r.impressions;
|
|
33568
33638
|
if (r.impressions > existing.bestPageImpressions) {
|
|
33569
|
-
existing.bestPage =
|
|
33639
|
+
existing.bestPage = page2;
|
|
33570
33640
|
existing.bestPageImpressions = r.impressions;
|
|
33571
33641
|
}
|
|
33572
33642
|
}
|
|
@@ -43227,21 +43297,21 @@ async function operationalLogsRoutes(app, opts = {}) {
|
|
|
43227
43297
|
if (!opts.listOperationalLogs) {
|
|
43228
43298
|
throw notImplemented("Operational logs are not available in this deployment.");
|
|
43229
43299
|
}
|
|
43230
|
-
const
|
|
43300
|
+
const page2 = operationalLogListDtoSchema.parse(await opts.listOperationalLogs(parsed.data));
|
|
43231
43301
|
reply.header("vary", OPERATIONAL_LOG_FIELDS_HEADER);
|
|
43232
|
-
return withoutUnrequestedFields(
|
|
43302
|
+
return withoutUnrequestedFields(page2, requestedFields(request.headers[OPERATIONAL_LOG_FIELDS_HEADER]));
|
|
43233
43303
|
});
|
|
43234
43304
|
}
|
|
43235
43305
|
function requestedFields(header2) {
|
|
43236
43306
|
const names = (Array.isArray(header2) ? header2 : [header2 ?? ""]).flatMap((value) => value.split(",")).map((name) => name.trim());
|
|
43237
43307
|
return new Set(OPERATIONAL_LOG_OPT_IN_CONTEXT_FIELDS.filter((field) => names.includes(field)));
|
|
43238
43308
|
}
|
|
43239
|
-
function withoutUnrequestedFields(
|
|
43309
|
+
function withoutUnrequestedFields(page2, requested) {
|
|
43240
43310
|
const omitted = OPERATIONAL_LOG_OPT_IN_CONTEXT_FIELDS.filter((field) => !requested.has(field));
|
|
43241
|
-
if (omitted.length === 0) return
|
|
43311
|
+
if (omitted.length === 0) return page2;
|
|
43242
43312
|
return {
|
|
43243
|
-
...
|
|
43244
|
-
entries:
|
|
43313
|
+
...page2,
|
|
43314
|
+
entries: page2.entries.map((entry) => ({
|
|
43245
43315
|
...entry,
|
|
43246
43316
|
context: Object.fromEntries(Object.entries(entry.context).filter(([key]) => !omitted.includes(key)))
|
|
43247
43317
|
}))
|
|
@@ -43877,7 +43947,7 @@ async function createLocalPost(token, account, location, content) {
|
|
|
43877
43947
|
async function listAccounts(accessToken, opts = {}) {
|
|
43878
43948
|
const collected = [];
|
|
43879
43949
|
let pageToken;
|
|
43880
|
-
let
|
|
43950
|
+
let page2 = 0;
|
|
43881
43951
|
do {
|
|
43882
43952
|
const url = new URL(`${GBP_ACCOUNT_MANAGEMENT_BASE}/accounts`);
|
|
43883
43953
|
url.searchParams.set("pageSize", String(GBP_DEFAULT_PAGE_SIZE));
|
|
@@ -43885,8 +43955,8 @@ async function listAccounts(accessToken, opts = {}) {
|
|
|
43885
43955
|
const res = await gbpFetchGet(url.toString(), accessToken, opts);
|
|
43886
43956
|
if (res.accounts) collected.push(...res.accounts);
|
|
43887
43957
|
pageToken = res.nextPageToken;
|
|
43888
|
-
|
|
43889
|
-
} while (pageToken &&
|
|
43958
|
+
page2++;
|
|
43959
|
+
} while (pageToken && page2 < GBP_MAX_PAGES);
|
|
43890
43960
|
return collected;
|
|
43891
43961
|
}
|
|
43892
43962
|
|
|
@@ -43895,7 +43965,7 @@ async function listLocations(accessToken, accountName, opts = {}) {
|
|
|
43895
43965
|
const readMask = opts.readMask ?? GBP_LOCATIONS_DEFAULT_READ_MASK;
|
|
43896
43966
|
const collected = [];
|
|
43897
43967
|
let pageToken;
|
|
43898
|
-
let
|
|
43968
|
+
let page2 = 0;
|
|
43899
43969
|
do {
|
|
43900
43970
|
const url = new URL(`${GBP_BUSINESS_INFO_BASE}/${accountName}/locations`);
|
|
43901
43971
|
url.searchParams.set("readMask", readMask);
|
|
@@ -43904,8 +43974,8 @@ async function listLocations(accessToken, accountName, opts = {}) {
|
|
|
43904
43974
|
const res = await gbpFetchGet(url.toString(), accessToken, opts);
|
|
43905
43975
|
if (res.locations) collected.push(...res.locations);
|
|
43906
43976
|
pageToken = res.nextPageToken;
|
|
43907
|
-
|
|
43908
|
-
} while (pageToken &&
|
|
43977
|
+
page2++;
|
|
43978
|
+
} while (pageToken && page2 < GBP_MAX_PAGES);
|
|
43909
43979
|
return collected;
|
|
43910
43980
|
}
|
|
43911
43981
|
function formatStorefrontAddress(loc) {
|
|
@@ -43976,7 +44046,7 @@ async function fetchDailyMetrics(accessToken, locationName, opts) {
|
|
|
43976
44046
|
async function listMonthlyKeywords(accessToken, locationName, opts) {
|
|
43977
44047
|
const collected = [];
|
|
43978
44048
|
let pageToken;
|
|
43979
|
-
let
|
|
44049
|
+
let page2 = 0;
|
|
43980
44050
|
do {
|
|
43981
44051
|
const params = new URLSearchParams();
|
|
43982
44052
|
params.set("monthlyRange.startMonth.year", String(opts.startMonth.year));
|
|
@@ -43997,8 +44067,8 @@ async function listMonthlyKeywords(accessToken, locationName, opts) {
|
|
|
43997
44067
|
});
|
|
43998
44068
|
}
|
|
43999
44069
|
pageToken = res.nextPageToken;
|
|
44000
|
-
|
|
44001
|
-
} while (pageToken &&
|
|
44070
|
+
page2++;
|
|
44071
|
+
} while (pageToken && page2 < GBP_MAX_PAGES);
|
|
44002
44072
|
return collected;
|
|
44003
44073
|
}
|
|
44004
44074
|
|
|
@@ -44006,7 +44076,7 @@ async function listMonthlyKeywords(accessToken, locationName, opts) {
|
|
|
44006
44076
|
async function listPlaceActionLinks(accessToken, locationName, opts = {}) {
|
|
44007
44077
|
const collected = [];
|
|
44008
44078
|
let pageToken;
|
|
44009
|
-
let
|
|
44079
|
+
let page2 = 0;
|
|
44010
44080
|
do {
|
|
44011
44081
|
const url = new URL(`${GBP_PLACE_ACTIONS_BASE}/${locationName}/placeActionLinks`);
|
|
44012
44082
|
url.searchParams.set("pageSize", String(GBP_DEFAULT_PAGE_SIZE));
|
|
@@ -44022,8 +44092,8 @@ async function listPlaceActionLinks(accessToken, locationName, opts = {}) {
|
|
|
44022
44092
|
});
|
|
44023
44093
|
}
|
|
44024
44094
|
pageToken = res.nextPageToken;
|
|
44025
|
-
|
|
44026
|
-
} while (pageToken &&
|
|
44095
|
+
page2++;
|
|
44096
|
+
} while (pageToken && page2 < GBP_MAX_PAGES);
|
|
44027
44097
|
return collected;
|
|
44028
44098
|
}
|
|
44029
44099
|
|
|
@@ -44143,14 +44213,14 @@ async function listReviews(accessToken, accountName, locationName, opts = {}) {
|
|
|
44143
44213
|
let totalReviewCount = null;
|
|
44144
44214
|
let stoppedEarly = false;
|
|
44145
44215
|
let pageToken;
|
|
44146
|
-
let
|
|
44216
|
+
let page2 = 0;
|
|
44147
44217
|
do {
|
|
44148
44218
|
const url = new URL(`${GBP_LEGACY_V4_BASE}/${accountName}/${locationName}/reviews`);
|
|
44149
44219
|
url.searchParams.set("pageSize", String(GBP_REVIEWS_PAGE_SIZE));
|
|
44150
44220
|
url.searchParams.set("orderBy", "updateTime desc");
|
|
44151
44221
|
if (pageToken) url.searchParams.set("pageToken", pageToken);
|
|
44152
44222
|
const res = await gbpFetchGet(url.toString(), accessToken, opts);
|
|
44153
|
-
if (
|
|
44223
|
+
if (page2 === 0) {
|
|
44154
44224
|
averageRating = typeof res.averageRating === "number" ? res.averageRating : null;
|
|
44155
44225
|
totalReviewCount = typeof res.totalReviewCount === "number" ? res.totalReviewCount : null;
|
|
44156
44226
|
}
|
|
@@ -44160,13 +44230,13 @@ async function listReviews(accessToken, accountName, locationName, opts = {}) {
|
|
|
44160
44230
|
const rows = mapped.filter((row) => row !== null);
|
|
44161
44231
|
reviews.push(...rows);
|
|
44162
44232
|
pageToken = res.nextPageToken;
|
|
44163
|
-
|
|
44233
|
+
page2++;
|
|
44164
44234
|
const oldest = rows.at(-1);
|
|
44165
44235
|
if (pageToken && opts.stopBefore && oldest && isNewestFirst(rows) && oldest.updateTime < opts.stopBefore) {
|
|
44166
44236
|
stoppedEarly = true;
|
|
44167
44237
|
break;
|
|
44168
44238
|
}
|
|
44169
|
-
} while (pageToken &&
|
|
44239
|
+
} while (pageToken && page2 < maxPages);
|
|
44170
44240
|
if (pageToken && !stoppedEarly) throw new Error("Review pagination is incomplete");
|
|
44171
44241
|
if (opts.strict && (new Set(reviews.map((row) => row.reviewName)).size !== reviews.length || totalReviewCount !== null && totalReviewCount !== reviews.length)) throw new Error("Review coverage is incomplete or changed during pagination");
|
|
44172
44242
|
return { reviews, averageRating, totalReviewCount, stoppedEarly };
|
|
@@ -45429,12 +45499,12 @@ async function gbpLocalPostsRoutes(app, options) {
|
|
|
45429
45499
|
request.query.accountName,
|
|
45430
45500
|
request.query.locationName
|
|
45431
45501
|
);
|
|
45432
|
-
const
|
|
45433
|
-
if (
|
|
45502
|
+
const page2 = request.query.pageToken;
|
|
45503
|
+
if (page2 !== void 0 && (page2.length > 2e3 || /[\p{Cc}\p{Cf}]/u.test(page2)))
|
|
45434
45504
|
throw validationError("Invalid GBP page token.");
|
|
45435
45505
|
return readPostResource(
|
|
45436
45506
|
project.canonicalDomain,
|
|
45437
|
-
(token) => listLocalPosts(token, location.accountName, location.locationName,
|
|
45507
|
+
(token) => listLocalPosts(token, location.accountName, location.locationName, page2),
|
|
45438
45508
|
"Google Local Posts could not be read; coverage is unknown."
|
|
45439
45509
|
);
|
|
45440
45510
|
});
|
|
@@ -46187,13 +46257,13 @@ function measurementDateRange(days) {
|
|
|
46187
46257
|
async function fetchPagedReport(accessToken, propertyId, baseRequest, pageSize = 1e4) {
|
|
46188
46258
|
const rows = [];
|
|
46189
46259
|
let offset = 0;
|
|
46190
|
-
for (let
|
|
46260
|
+
for (let page2 = 0; page2 < GA4_MAX_PAGES; page2++) {
|
|
46191
46261
|
const response = await runReport(accessToken, propertyId, { ...baseRequest, limit: pageSize, offset });
|
|
46192
46262
|
const pageRows = response.rows ?? [];
|
|
46193
46263
|
rows.push(...pageRows);
|
|
46194
46264
|
offset += pageRows.length;
|
|
46195
46265
|
if (pageRows.length < pageSize || response.rowCount !== void 0 && offset >= response.rowCount) break;
|
|
46196
|
-
if (
|
|
46266
|
+
if (page2 === GA4_MAX_PAGES - 1) {
|
|
46197
46267
|
throw new Error(`GA4 report truncated: page limit (${GA4_MAX_PAGES}) reached before all rows were fetched`);
|
|
46198
46268
|
}
|
|
46199
46269
|
}
|
|
@@ -46206,7 +46276,7 @@ async function fetchPagedReportWithTotals(accessToken, propertyId, baseRequest,
|
|
|
46206
46276
|
let firstPage;
|
|
46207
46277
|
let reportedRowCount;
|
|
46208
46278
|
let offset = 0;
|
|
46209
|
-
for (let
|
|
46279
|
+
for (let page2 = 0; page2 < GA4_MAX_PAGES; page2++) {
|
|
46210
46280
|
const limit = Math.min(pageSize, maxRows - rows.length);
|
|
46211
46281
|
const response = await runReport(accessToken, propertyId, { ...baseRequest, limit, offset });
|
|
46212
46282
|
firstPage ??= response;
|
|
@@ -47604,7 +47674,7 @@ async function googleRoutes(app, opts) {
|
|
|
47604
47674
|
});
|
|
47605
47675
|
app.get("/projects/:name/google/gsc/performance", async (request) => {
|
|
47606
47676
|
const project = resolveProject(app.db, request.params.name);
|
|
47607
|
-
const { startDate, endDate, query, page:
|
|
47677
|
+
const { startDate, endDate, query, page: page2, limit, offset } = request.query;
|
|
47608
47678
|
const parsedOrderBy = gscPerformanceOrderBySchema.safeParse(request.query.orderBy ?? "clicks");
|
|
47609
47679
|
if (!parsedOrderBy.success) {
|
|
47610
47680
|
throw validationError(
|
|
@@ -47626,7 +47696,7 @@ async function googleRoutes(app, opts) {
|
|
|
47626
47696
|
else if (cutoffDate) conditions.push(sql21`${gscSearchData.date} >= ${cutoffDate}`);
|
|
47627
47697
|
if (effectiveEndDate) conditions.push(sql21`${gscSearchData.date} <= ${effectiveEndDate}`);
|
|
47628
47698
|
if (query) conditions.push(sql21`${gscSearchData.query} LIKE ${"%" + escapeLikePattern(query) + "%"} ESCAPE '\\'`);
|
|
47629
|
-
if (
|
|
47699
|
+
if (page2) conditions.push(sql21`${gscSearchData.page} LIKE ${"%" + escapeLikePattern(page2) + "%"} ESCAPE '\\'`);
|
|
47630
47700
|
const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
|
|
47631
47701
|
const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
|
|
47632
47702
|
const orderColumns = {
|
|
@@ -50252,11 +50322,11 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
50252
50322
|
}
|
|
50253
50323
|
const limit = query.limit ?? 50;
|
|
50254
50324
|
const rows = app.db.select().from(googleAdsRawSnapshots).where(and55(...conditions)).orderBy(desc32(googleAdsRawSnapshots.capturedAt), desc32(googleAdsRawSnapshots.id)).limit(limit + 1).all();
|
|
50255
|
-
const
|
|
50325
|
+
const page2 = rows.slice(0, limit);
|
|
50256
50326
|
const total = app.db.select({ total: sql22`COUNT(*)`.mapWith(Number).as("total") }).from(googleAdsRawSnapshots).where(eq67(googleAdsRawSnapshots.projectId, project.id)).get();
|
|
50257
50327
|
return {
|
|
50258
|
-
snapshots:
|
|
50259
|
-
nextCursor: rows.length > limit &&
|
|
50328
|
+
snapshots: page2.map(toGoogleAdsSnapshotMetadata),
|
|
50329
|
+
nextCursor: rows.length > limit && page2.length > 0 ? encodeSnapshotCursor({ capturedAt: page2.at(-1).capturedAt, id: page2.at(-1).id }) : null,
|
|
50260
50330
|
total: total?.total ?? 0
|
|
50261
50331
|
};
|
|
50262
50332
|
});
|
|
@@ -50284,11 +50354,11 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
50284
50354
|
}
|
|
50285
50355
|
const limit = query.limit ?? 50;
|
|
50286
50356
|
const rows = app.db.select().from(gtmRawSnapshots).where(and55(...conditions)).orderBy(desc32(gtmRawSnapshots.capturedAt), desc32(gtmRawSnapshots.id)).limit(limit + 1).all();
|
|
50287
|
-
const
|
|
50357
|
+
const page2 = rows.slice(0, limit);
|
|
50288
50358
|
const total = app.db.select({ total: sql22`COUNT(*)`.mapWith(Number).as("total") }).from(gtmRawSnapshots).where(eq67(gtmRawSnapshots.projectId, project.id)).get();
|
|
50289
50359
|
return {
|
|
50290
|
-
snapshots:
|
|
50291
|
-
nextCursor: rows.length > limit &&
|
|
50360
|
+
snapshots: page2.map(toGtmSnapshotMetadata),
|
|
50361
|
+
nextCursor: rows.length > limit && page2.length > 0 ? encodeSnapshotCursor({ capturedAt: page2.at(-1).capturedAt, id: page2.at(-1).id }) : null,
|
|
50292
50362
|
total: total?.total ?? 0
|
|
50293
50363
|
};
|
|
50294
50364
|
});
|
|
@@ -54733,11 +54803,11 @@ async function adsRoutes(app, opts) {
|
|
|
54733
54803
|
) : void 0
|
|
54734
54804
|
)).orderBy(asc15(adsOperations.createdAt), asc15(adsOperations.id)).limit(parsed.data.limit + 1).all();
|
|
54735
54805
|
const hasMore = rows.length > parsed.data.limit;
|
|
54736
|
-
const
|
|
54806
|
+
const page2 = hasMore ? rows.slice(0, parsed.data.limit) : rows;
|
|
54737
54807
|
const response = {
|
|
54738
|
-
operations:
|
|
54739
|
-
count:
|
|
54740
|
-
nextCursor: hasMore &&
|
|
54808
|
+
operations: page2.map(operationDto),
|
|
54809
|
+
count: page2.length,
|
|
54810
|
+
nextCursor: hasMore && page2.length > 0 ? encodeAdsOperationCursor(project.id, parsed.data.state, page2[page2.length - 1]) : null
|
|
54741
54811
|
};
|
|
54742
54812
|
return response;
|
|
54743
54813
|
});
|
|
@@ -58863,9 +58933,9 @@ function contentHash(content) {
|
|
|
58863
58933
|
return crypto48.createHash("sha256").update(content).digest("hex");
|
|
58864
58934
|
}
|
|
58865
58935
|
function buildAmbiguousSlugMessage(slug, pages) {
|
|
58866
|
-
const candidates = pages.map((
|
|
58867
|
-
const title = stripHtml(
|
|
58868
|
-
return `#${
|
|
58936
|
+
const candidates = pages.map((page2) => {
|
|
58937
|
+
const title = stripHtml(page2.title?.rendered ?? "") || "(untitled)";
|
|
58938
|
+
return `#${page2.id} "${title}"`;
|
|
58869
58939
|
}).join(", ");
|
|
58870
58940
|
return `Multiple pages matched slug "${slug}". Candidates: ${candidates}.`;
|
|
58871
58941
|
}
|
|
@@ -58899,9 +58969,9 @@ function resolveSeoWriteTargets(meta, plugins) {
|
|
|
58899
58969
|
}
|
|
58900
58970
|
return [...new Set(targets)];
|
|
58901
58971
|
}
|
|
58902
|
-
function buildSeoState(
|
|
58972
|
+
function buildSeoState(page2, html, plugins) {
|
|
58903
58973
|
const renderedSeo = html ? summarizeSeoFromHtml(html) : { title: null, description: null, noindex: null };
|
|
58904
|
-
const writeTargets = resolveSeoWriteTargets(
|
|
58974
|
+
const writeTargets = resolveSeoWriteTargets(page2.meta, plugins);
|
|
58905
58975
|
return {
|
|
58906
58976
|
title: renderedSeo.title,
|
|
58907
58977
|
description: renderedSeo.description,
|
|
@@ -58970,17 +59040,17 @@ async function listActivePlugins(connection, env) {
|
|
|
58970
59040
|
const site = resolveEnvironment(connection, env);
|
|
58971
59041
|
try {
|
|
58972
59042
|
const allPlugins = [];
|
|
58973
|
-
let
|
|
59043
|
+
let page2 = 1;
|
|
58974
59044
|
let totalPages = 1;
|
|
58975
|
-
while (
|
|
59045
|
+
while (page2 <= totalPages) {
|
|
58976
59046
|
const { body, response } = await fetchJson(
|
|
58977
59047
|
connection,
|
|
58978
59048
|
site.siteUrl,
|
|
58979
|
-
`/wp-json/wp/v2/plugins?per_page=100&page=${
|
|
59049
|
+
`/wp-json/wp/v2/plugins?per_page=100&page=${page2}&_fields=plugin,status`
|
|
58980
59050
|
);
|
|
58981
59051
|
totalPages = Number.parseInt(response.headers.get("x-wp-totalpages") ?? "1", 10) || 1;
|
|
58982
59052
|
allPlugins.push(...body);
|
|
58983
|
-
|
|
59053
|
+
page2 += 1;
|
|
58984
59054
|
}
|
|
58985
59055
|
return allPlugins.filter((plugin) => plugin.status === "active").map((plugin) => plugin.plugin).sort();
|
|
58986
59056
|
} catch (error) {
|
|
@@ -58993,13 +59063,13 @@ async function listActivePlugins(connection, env) {
|
|
|
58993
59063
|
async function listPages(connection, env) {
|
|
58994
59064
|
const site = resolveEnvironment(connection, env);
|
|
58995
59065
|
const pages = [];
|
|
58996
|
-
let
|
|
59066
|
+
let page2 = 1;
|
|
58997
59067
|
let totalPages = 1;
|
|
58998
|
-
while (
|
|
59068
|
+
while (page2 <= totalPages) {
|
|
58999
59069
|
const { body, response } = await fetchJson(
|
|
59000
59070
|
connection,
|
|
59001
59071
|
site.siteUrl,
|
|
59002
|
-
`/wp-json/wp/v2/pages?per_page=100&page=${
|
|
59072
|
+
`/wp-json/wp/v2/pages?per_page=100&page=${page2}&context=edit&_fields=${PAGE_LIST_FIELDS}`
|
|
59003
59073
|
);
|
|
59004
59074
|
totalPages = Number.parseInt(response.headers.get("x-wp-totalpages") ?? "1", 10) || 1;
|
|
59005
59075
|
pages.push(...body.map((entry) => ({
|
|
@@ -59010,7 +59080,7 @@ async function listPages(connection, env) {
|
|
|
59010
59080
|
modifiedAt: entry.modified ?? entry.modified_gmt ?? null,
|
|
59011
59081
|
link: entry.link ?? null
|
|
59012
59082
|
})));
|
|
59013
|
-
|
|
59083
|
+
page2 += 1;
|
|
59014
59084
|
}
|
|
59015
59085
|
return pages;
|
|
59016
59086
|
}
|
|
@@ -59024,7 +59094,7 @@ async function getPageBySlug(connection, slug, env) {
|
|
|
59024
59094
|
if (body.length === 0) {
|
|
59025
59095
|
throw new WordpressApiError("NOT_FOUND", `No WordPress page found for slug "${slug}"`, 404);
|
|
59026
59096
|
}
|
|
59027
|
-
const exact = body.filter((
|
|
59097
|
+
const exact = body.filter((page2) => page2.slug === slug);
|
|
59028
59098
|
if (exact.length === 1) return exact[0];
|
|
59029
59099
|
if (exact.length > 1) {
|
|
59030
59100
|
throw new WordpressApiError("VALIDATION_ERROR", buildAmbiguousSlugMessage(slug, exact), 400);
|
|
@@ -59041,19 +59111,19 @@ async function fetchRenderedPage(connection, link) {
|
|
|
59041
59111
|
async function getPageDetail(connection, slug, env, plugins) {
|
|
59042
59112
|
const site = resolveEnvironment(connection, env);
|
|
59043
59113
|
const resolvedPlugins = plugins === void 0 ? await listActivePlugins(connection, site.env) : plugins;
|
|
59044
|
-
const
|
|
59045
|
-
const html = await fetchRenderedPage(connection,
|
|
59114
|
+
const page2 = await getPageBySlug(connection, slug, site.env);
|
|
59115
|
+
const html = await fetchRenderedPage(connection, page2.link);
|
|
59046
59116
|
const schemaBlocks = html ? extractSchemaBlocks(html) : [];
|
|
59047
|
-
const seo = buildSeoState(
|
|
59117
|
+
const seo = buildSeoState(page2, html, resolvedPlugins);
|
|
59048
59118
|
return {
|
|
59049
|
-
id:
|
|
59050
|
-
slug:
|
|
59051
|
-
title: stripHtml(
|
|
59052
|
-
status:
|
|
59053
|
-
modifiedAt:
|
|
59054
|
-
link:
|
|
59119
|
+
id: page2.id,
|
|
59120
|
+
slug: page2.slug,
|
|
59121
|
+
title: stripHtml(page2.title?.rendered ?? ""),
|
|
59122
|
+
status: page2.status,
|
|
59123
|
+
modifiedAt: page2.modified ?? page2.modified_gmt ?? null,
|
|
59124
|
+
link: page2.link ?? null,
|
|
59055
59125
|
env: site.env,
|
|
59056
|
-
content:
|
|
59126
|
+
content: page2.content?.raw ?? page2.content?.rendered ?? "",
|
|
59057
59127
|
seo,
|
|
59058
59128
|
schemaBlocks
|
|
59059
59129
|
};
|
|
@@ -59078,11 +59148,11 @@ async function createPage(connection, body, env) {
|
|
|
59078
59148
|
}
|
|
59079
59149
|
async function updatePageBySlug(connection, slug, body, env) {
|
|
59080
59150
|
const site = resolveEnvironment(connection, env);
|
|
59081
|
-
const
|
|
59151
|
+
const page2 = await getPageBySlug(connection, slug, site.env);
|
|
59082
59152
|
const { body: updated } = await fetchJson(
|
|
59083
59153
|
connection,
|
|
59084
59154
|
site.siteUrl,
|
|
59085
|
-
`/wp-json/wp/v2/pages/${
|
|
59155
|
+
`/wp-json/wp/v2/pages/${page2.id}`,
|
|
59086
59156
|
{
|
|
59087
59157
|
method: "POST",
|
|
59088
59158
|
body: JSON.stringify(body)
|
|
@@ -59099,9 +59169,9 @@ function encodeNoindexValue(key, value) {
|
|
|
59099
59169
|
async function setSeoMeta(connection, slug, body, env) {
|
|
59100
59170
|
const site = resolveEnvironment(connection, env);
|
|
59101
59171
|
const plugins = await listActivePlugins(connection, site.env);
|
|
59102
|
-
const
|
|
59103
|
-
const writeTargets = resolveSeoWriteTargets(
|
|
59104
|
-
if (writeTargets.length === 0 || !
|
|
59172
|
+
const page2 = await getPageBySlug(connection, slug, site.env);
|
|
59173
|
+
const writeTargets = resolveSeoWriteTargets(page2.meta, plugins);
|
|
59174
|
+
if (writeTargets.length === 0 || !page2.meta) {
|
|
59105
59175
|
throw new WordpressApiError("UNSUPPORTED", "This WordPress site does not expose writable SEO meta fields through REST. Update the meta manually in WordPress.", 400);
|
|
59106
59176
|
}
|
|
59107
59177
|
const patch = {};
|
|
@@ -59118,12 +59188,12 @@ async function setSeoMeta(connection, slug, body, env) {
|
|
|
59118
59188
|
await fetchJson(
|
|
59119
59189
|
connection,
|
|
59120
59190
|
site.siteUrl,
|
|
59121
|
-
`/wp-json/wp/v2/pages/${
|
|
59191
|
+
`/wp-json/wp/v2/pages/${page2.id}`,
|
|
59122
59192
|
{
|
|
59123
59193
|
method: "POST",
|
|
59124
59194
|
body: JSON.stringify({
|
|
59125
59195
|
meta: {
|
|
59126
|
-
...
|
|
59196
|
+
...page2.meta ?? {},
|
|
59127
59197
|
...patch
|
|
59128
59198
|
}
|
|
59129
59199
|
})
|
|
@@ -59171,7 +59241,7 @@ async function bulkSetSeoMeta(connection, entries, env) {
|
|
|
59171
59241
|
3,
|
|
59172
59242
|
async (entry) => {
|
|
59173
59243
|
try {
|
|
59174
|
-
const
|
|
59244
|
+
const page2 = await getPageBySlug(connection, entry.slug, site.env);
|
|
59175
59245
|
if (strategy === "manual") {
|
|
59176
59246
|
return {
|
|
59177
59247
|
slug: entry.slug,
|
|
@@ -59179,20 +59249,20 @@ async function bulkSetSeoMeta(connection, entries, env) {
|
|
|
59179
59249
|
manualAssist: buildManualMetaAssist(
|
|
59180
59250
|
site.siteUrl,
|
|
59181
59251
|
entry.slug,
|
|
59182
|
-
|
|
59252
|
+
page2.link,
|
|
59183
59253
|
entry
|
|
59184
59254
|
)
|
|
59185
59255
|
};
|
|
59186
59256
|
}
|
|
59187
|
-
const writeTargets = resolveSeoWriteTargets(
|
|
59188
|
-
if (writeTargets.length === 0 || !
|
|
59257
|
+
const writeTargets = resolveSeoWriteTargets(page2.meta, plugins);
|
|
59258
|
+
if (writeTargets.length === 0 || !page2.meta) {
|
|
59189
59259
|
return {
|
|
59190
59260
|
slug: entry.slug,
|
|
59191
59261
|
status: "manual",
|
|
59192
59262
|
manualAssist: buildManualMetaAssist(
|
|
59193
59263
|
site.siteUrl,
|
|
59194
59264
|
entry.slug,
|
|
59195
|
-
|
|
59265
|
+
page2.link,
|
|
59196
59266
|
entry
|
|
59197
59267
|
)
|
|
59198
59268
|
};
|
|
@@ -59212,7 +59282,7 @@ async function bulkSetSeoMeta(connection, entries, env) {
|
|
|
59212
59282
|
manualAssist: buildManualMetaAssist(
|
|
59213
59283
|
site.siteUrl,
|
|
59214
59284
|
entry.slug,
|
|
59215
|
-
|
|
59285
|
+
page2.link,
|
|
59216
59286
|
entry
|
|
59217
59287
|
)
|
|
59218
59288
|
};
|
|
@@ -59220,11 +59290,11 @@ async function bulkSetSeoMeta(connection, entries, env) {
|
|
|
59220
59290
|
await fetchJson(
|
|
59221
59291
|
connection,
|
|
59222
59292
|
site.siteUrl,
|
|
59223
|
-
`/wp-json/wp/v2/pages/${
|
|
59293
|
+
`/wp-json/wp/v2/pages/${page2.id}`,
|
|
59224
59294
|
{
|
|
59225
59295
|
method: "POST",
|
|
59226
59296
|
body: JSON.stringify({
|
|
59227
|
-
meta: { ...
|
|
59297
|
+
meta: { ...page2.meta ?? {}, ...patch }
|
|
59228
59298
|
})
|
|
59229
59299
|
}
|
|
59230
59300
|
);
|
|
@@ -59264,20 +59334,20 @@ ${CANONRY_SCHEMA_END}`;
|
|
|
59264
59334
|
return stripped + injection;
|
|
59265
59335
|
}
|
|
59266
59336
|
async function verifySchemaInjection(connection, slug, env) {
|
|
59267
|
-
const
|
|
59268
|
-
const raw =
|
|
59337
|
+
const page2 = await getPageBySlug(connection, slug, env);
|
|
59338
|
+
const raw = page2.content?.raw ?? page2.content?.rendered ?? "";
|
|
59269
59339
|
return raw.includes(CANONRY_SCHEMA_START);
|
|
59270
59340
|
}
|
|
59271
59341
|
async function deploySchema(connection, slug, schemas, env) {
|
|
59272
59342
|
const site = resolveEnvironment(connection, env);
|
|
59273
59343
|
try {
|
|
59274
|
-
const
|
|
59275
|
-
const currentContent =
|
|
59344
|
+
const page2 = await getPageBySlug(connection, slug, site.env);
|
|
59345
|
+
const currentContent = page2.content?.raw ?? page2.content?.rendered ?? "";
|
|
59276
59346
|
const updatedContent = injectCanonrySchema(currentContent, schemas);
|
|
59277
59347
|
await fetchJson(
|
|
59278
59348
|
connection,
|
|
59279
59349
|
site.siteUrl,
|
|
59280
|
-
`/wp-json/wp/v2/pages/${
|
|
59350
|
+
`/wp-json/wp/v2/pages/${page2.id}`,
|
|
59281
59351
|
{
|
|
59282
59352
|
method: "POST",
|
|
59283
59353
|
body: JSON.stringify({ content: updatedContent })
|
|
@@ -59291,7 +59361,7 @@ async function deploySchema(connection, slug, schemas, env) {
|
|
|
59291
59361
|
schemasInjected: schemas.map((s) => typeof s["@type"] === "string" ? s["@type"] : "Unknown"),
|
|
59292
59362
|
manualAssist: {
|
|
59293
59363
|
manualRequired: true,
|
|
59294
|
-
targetUrl:
|
|
59364
|
+
targetUrl: page2.link ?? `${site.siteUrl}/${slug}`,
|
|
59295
59365
|
adminUrl: `${site.siteUrl}/wp-admin/`,
|
|
59296
59366
|
content: schemas.map((s) => JSON.stringify(s, null, 2)).join("\n\n"),
|
|
59297
59367
|
nextSteps: [
|
|
@@ -59346,12 +59416,12 @@ async function getSchemaStatus(connection, env) {
|
|
|
59346
59416
|
const details = await mapWithConcurrency2(
|
|
59347
59417
|
pages,
|
|
59348
59418
|
5,
|
|
59349
|
-
async (
|
|
59419
|
+
async (page2) => getPageDetail(connection, page2.slug, site.env)
|
|
59350
59420
|
);
|
|
59351
|
-
const statusPages = details.map((
|
|
59352
|
-
const rawContent =
|
|
59421
|
+
const statusPages = details.map((page2) => {
|
|
59422
|
+
const rawContent = page2.content;
|
|
59353
59423
|
const hasCanonryMarker = rawContent.includes(CANONRY_SCHEMA_START);
|
|
59354
|
-
const allSchemaTypes =
|
|
59424
|
+
const allSchemaTypes = page2.schemaBlocks.map((b) => b.type);
|
|
59355
59425
|
const canonrySchemas = [];
|
|
59356
59426
|
const thirdPartySchemas = [];
|
|
59357
59427
|
if (hasCanonryMarker) {
|
|
@@ -59384,8 +59454,8 @@ async function getSchemaStatus(connection, env) {
|
|
|
59384
59454
|
}
|
|
59385
59455
|
}
|
|
59386
59456
|
return {
|
|
59387
|
-
slug:
|
|
59388
|
-
title:
|
|
59457
|
+
slug: page2.slug,
|
|
59458
|
+
title: page2.title,
|
|
59389
59459
|
canonrySchemas,
|
|
59390
59460
|
thirdPartySchemas,
|
|
59391
59461
|
hasCanonrySchema: hasCanonryMarker
|
|
@@ -59427,14 +59497,14 @@ async function getPageSchema(connection, slug, env) {
|
|
|
59427
59497
|
}
|
|
59428
59498
|
async function buildManualSchemaUpdate(connection, slug, body, env) {
|
|
59429
59499
|
const site = resolveEnvironment(connection, env);
|
|
59430
|
-
const
|
|
59500
|
+
const page2 = await getPageBySlug(connection, slug, site.env);
|
|
59431
59501
|
return {
|
|
59432
59502
|
manualRequired: true,
|
|
59433
|
-
targetUrl:
|
|
59503
|
+
targetUrl: page2.link ?? `${site.siteUrl}/${slug}`,
|
|
59434
59504
|
adminUrl: `${site.siteUrl}/wp-admin/`,
|
|
59435
59505
|
content: body.json,
|
|
59436
59506
|
nextSteps: [
|
|
59437
|
-
`Open the WordPress editor or theme/plugin settings for ${
|
|
59507
|
+
`Open the WordPress editor or theme/plugin settings for ${page2.slug}.`,
|
|
59438
59508
|
`Add the ${body.type ?? "custom"} JSON-LD block to the page or the site-level schema tool you use.`,
|
|
59439
59509
|
"Publish/update the page and refresh the public URL to confirm the JSON-LD block is rendered."
|
|
59440
59510
|
]
|
|
@@ -59447,33 +59517,33 @@ async function runAudit(connection, env) {
|
|
|
59447
59517
|
const details = await mapWithConcurrency2(
|
|
59448
59518
|
pages,
|
|
59449
59519
|
5,
|
|
59450
|
-
async (
|
|
59520
|
+
async (page2) => getPageDetail(connection, page2.slug, site.env, plugins)
|
|
59451
59521
|
);
|
|
59452
59522
|
const auditPages = [];
|
|
59453
59523
|
const allIssues = [];
|
|
59454
|
-
for (const
|
|
59524
|
+
for (const page2 of details) {
|
|
59455
59525
|
const issues = [];
|
|
59456
|
-
const wordCount = computeWordCount(
|
|
59457
|
-
const schemaPresent =
|
|
59458
|
-
if (
|
|
59526
|
+
const wordCount = computeWordCount(page2.content);
|
|
59527
|
+
const schemaPresent = page2.schemaBlocks.length > 0;
|
|
59528
|
+
if (page2.status === "publish" && page2.seo.noindex === true) {
|
|
59459
59529
|
issues.push({
|
|
59460
|
-
slug:
|
|
59530
|
+
slug: page2.slug,
|
|
59461
59531
|
severity: "high",
|
|
59462
59532
|
code: "noindex",
|
|
59463
59533
|
message: "Published page is marked noindex."
|
|
59464
59534
|
});
|
|
59465
59535
|
}
|
|
59466
|
-
if (!
|
|
59536
|
+
if (!page2.seo.title) {
|
|
59467
59537
|
issues.push({
|
|
59468
|
-
slug:
|
|
59538
|
+
slug: page2.slug,
|
|
59469
59539
|
severity: "medium",
|
|
59470
59540
|
code: "missing-seo-title",
|
|
59471
59541
|
message: "Rendered page title is missing."
|
|
59472
59542
|
});
|
|
59473
59543
|
}
|
|
59474
|
-
if (!
|
|
59544
|
+
if (!page2.seo.description) {
|
|
59475
59545
|
issues.push({
|
|
59476
|
-
slug:
|
|
59546
|
+
slug: page2.slug,
|
|
59477
59547
|
severity: "medium",
|
|
59478
59548
|
code: "missing-meta-description",
|
|
59479
59549
|
message: "Rendered meta description is missing."
|
|
@@ -59481,7 +59551,7 @@ async function runAudit(connection, env) {
|
|
|
59481
59551
|
}
|
|
59482
59552
|
if (!schemaPresent) {
|
|
59483
59553
|
issues.push({
|
|
59484
|
-
slug:
|
|
59554
|
+
slug: page2.slug,
|
|
59485
59555
|
severity: "medium",
|
|
59486
59556
|
code: "missing-schema",
|
|
59487
59557
|
message: "No JSON-LD schema was detected on the rendered page."
|
|
@@ -59489,18 +59559,18 @@ async function runAudit(connection, env) {
|
|
|
59489
59559
|
}
|
|
59490
59560
|
if (wordCount < THIN_CONTENT_WORD_COUNT) {
|
|
59491
59561
|
issues.push({
|
|
59492
|
-
slug:
|
|
59562
|
+
slug: page2.slug,
|
|
59493
59563
|
severity: "low",
|
|
59494
59564
|
code: "thin-content",
|
|
59495
59565
|
message: `Page content is thin (${wordCount} words; target at least ${THIN_CONTENT_WORD_COUNT}).`
|
|
59496
59566
|
});
|
|
59497
59567
|
}
|
|
59498
59568
|
auditPages.push({
|
|
59499
|
-
slug:
|
|
59500
|
-
title:
|
|
59501
|
-
status:
|
|
59569
|
+
slug: page2.slug,
|
|
59570
|
+
title: page2.title,
|
|
59571
|
+
status: page2.status,
|
|
59502
59572
|
wordCount,
|
|
59503
|
-
seo:
|
|
59573
|
+
seo: page2.seo,
|
|
59504
59574
|
schemaPresent,
|
|
59505
59575
|
issues
|
|
59506
59576
|
});
|
|
@@ -60085,19 +60155,19 @@ async function wordpressRoutes(app, opts) {
|
|
|
60085
60155
|
for (const issue of auditIssues) {
|
|
60086
60156
|
if (issue.code === "missing-meta-description" || issue.code === "missing-seo-title") {
|
|
60087
60157
|
const existing = metaEntries.find((e) => e.slug === issue.slug);
|
|
60088
|
-
const
|
|
60158
|
+
const page2 = auditPages.find((p) => p.slug === issue.slug);
|
|
60089
60159
|
if (!existing) {
|
|
60090
60160
|
metaEntries.push({
|
|
60091
60161
|
slug: issue.slug,
|
|
60092
|
-
title: issue.code === "missing-seo-title" ?
|
|
60093
|
-
description: issue.code === "missing-meta-description" ?
|
|
60162
|
+
title: issue.code === "missing-seo-title" ? page2?.title ?? issue.slug : void 0,
|
|
60163
|
+
description: issue.code === "missing-meta-description" ? page2?.title ?? issue.slug : void 0
|
|
60094
60164
|
});
|
|
60095
60165
|
} else {
|
|
60096
60166
|
if (issue.code === "missing-seo-title" && !existing.title) {
|
|
60097
|
-
existing.title =
|
|
60167
|
+
existing.title = page2?.title ?? issue.slug;
|
|
60098
60168
|
}
|
|
60099
60169
|
if (issue.code === "missing-meta-description" && !existing.description) {
|
|
60100
|
-
existing.description =
|
|
60170
|
+
existing.description = page2?.title ?? issue.slug;
|
|
60101
60171
|
}
|
|
60102
60172
|
}
|
|
60103
60173
|
}
|
|
@@ -61310,7 +61380,7 @@ async function listCloudRunTrafficEvents(accessToken, options) {
|
|
|
61310
61380
|
let skippedEntryCount = 0;
|
|
61311
61381
|
const events = [];
|
|
61312
61382
|
const orderBy = options.orderBy ?? (options.firstSync ? "timestamp desc" : "timestamp asc");
|
|
61313
|
-
for (let
|
|
61383
|
+
for (let page2 = 0; page2 < maxPages; page2 += 1) {
|
|
61314
61384
|
const requestBody = {
|
|
61315
61385
|
resourceNames: [`projects/${options.gcpProjectId}`],
|
|
61316
61386
|
filter,
|
|
@@ -61551,7 +61621,7 @@ async function listWordpressTrafficEvents(options) {
|
|
|
61551
61621
|
let hasMore = false;
|
|
61552
61622
|
const events = [];
|
|
61553
61623
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
61554
|
-
for (let
|
|
61624
|
+
for (let page2 = 0; page2 < maxPages; page2 += 1) {
|
|
61555
61625
|
const url = new URL(endpoint);
|
|
61556
61626
|
url.searchParams.set("limit", String(pageSize));
|
|
61557
61627
|
if (cursor !== void 0 && cursor !== "") {
|
|
@@ -61789,12 +61859,12 @@ async function listVercelTrafficEvents(options) {
|
|
|
61789
61859
|
let skippedEntryCount = 0;
|
|
61790
61860
|
let hasMore = false;
|
|
61791
61861
|
const events = [];
|
|
61792
|
-
for (let
|
|
61862
|
+
for (let page2 = 0; page2 < maxPages; page2 += 1) {
|
|
61793
61863
|
const url = new URL(VERCEL_REQUEST_LOGS_URL);
|
|
61794
61864
|
url.searchParams.set("projectId", projectId);
|
|
61795
61865
|
url.searchParams.set("ownerId", teamId);
|
|
61796
61866
|
url.searchParams.set("teamId", teamId);
|
|
61797
|
-
url.searchParams.set("page", String(
|
|
61867
|
+
url.searchParams.set("page", String(page2));
|
|
61798
61868
|
url.searchParams.set("startDate", startDate);
|
|
61799
61869
|
url.searchParams.set("endDate", endDate);
|
|
61800
61870
|
url.searchParams.set("environment", environment);
|
|
@@ -61926,9 +61996,9 @@ async function drainVercelTrafficEvents(options) {
|
|
|
61926
61996
|
const subSpanMs = subEndMs - cursorMs;
|
|
61927
61997
|
const useFloorPageBudget = subSpanMs <= MIN_SUB_WINDOW_MS && floorPageBudgetCountdown > 0;
|
|
61928
61998
|
const pageBudget = useFloorPageBudget ? FLOOR_SLICE_MAX_PAGES : options.pagesPerSubWindow;
|
|
61929
|
-
let
|
|
61999
|
+
let page2;
|
|
61930
62000
|
try {
|
|
61931
|
-
|
|
62001
|
+
page2 = await options.pull({
|
|
61932
62002
|
token: options.token,
|
|
61933
62003
|
projectId: options.projectId,
|
|
61934
62004
|
teamId: options.teamId,
|
|
@@ -61950,7 +62020,7 @@ async function drainVercelTrafficEvents(options) {
|
|
|
61950
62020
|
throw error;
|
|
61951
62021
|
}
|
|
61952
62022
|
subWindowCount += 1;
|
|
61953
|
-
if (
|
|
62023
|
+
if (page2.hasMore) {
|
|
61954
62024
|
if (subSpanMs > MIN_SUB_WINDOW_MS) {
|
|
61955
62025
|
spanMs = Math.max(Math.floor(subSpanMs / 2), MIN_SUB_WINDOW_MS);
|
|
61956
62026
|
if (spanMs === MIN_SUB_WINDOW_MS) {
|
|
@@ -61959,7 +62029,7 @@ async function drainVercelTrafficEvents(options) {
|
|
|
61959
62029
|
continue;
|
|
61960
62030
|
}
|
|
61961
62031
|
if (pageBudget < FLOOR_SLICE_MAX_PAGES) {
|
|
61962
|
-
|
|
62032
|
+
page2 = await options.pull({
|
|
61963
62033
|
token: options.token,
|
|
61964
62034
|
projectId: options.projectId,
|
|
61965
62035
|
teamId: options.teamId,
|
|
@@ -61972,7 +62042,7 @@ async function drainVercelTrafficEvents(options) {
|
|
|
61972
62042
|
floorSpanProbeCountdown = FLOOR_CONGESTION_PROBE_INTERVAL;
|
|
61973
62043
|
floorPageBudgetCountdown = FLOOR_CONGESTION_PROBE_INTERVAL;
|
|
61974
62044
|
}
|
|
61975
|
-
if (
|
|
62045
|
+
if (page2.hasMore) {
|
|
61976
62046
|
if (options.abortOnTruncation) {
|
|
61977
62047
|
throw new Error(
|
|
61978
62048
|
`Vercel ${MIN_SUB_WINDOW_MS / 1e3}-second slice starting ${new Date(cursorMs).toISOString()} holds more than ${FLOOR_SLICE_MAX_PAGES} pages and cannot be drained further`
|
|
@@ -61982,7 +62052,7 @@ async function drainVercelTrafficEvents(options) {
|
|
|
61982
62052
|
truncatedSliceStartsMs.push(cursorMs);
|
|
61983
62053
|
}
|
|
61984
62054
|
}
|
|
61985
|
-
for (const event of
|
|
62055
|
+
for (const event of page2.events) {
|
|
61986
62056
|
if (!seenEventIds.has(event.eventId)) {
|
|
61987
62057
|
seenEventIds.add(event.eventId);
|
|
61988
62058
|
events.push(event);
|
|
@@ -64965,7 +65035,7 @@ async function trafficRoutes(app, opts) {
|
|
|
64965
65035
|
}
|
|
64966
65036
|
const isFirstSync = !sourceRow2.lastSyncedAt;
|
|
64967
65037
|
try {
|
|
64968
|
-
const
|
|
65038
|
+
const page2 = await pullEvents(accessToken, {
|
|
64969
65039
|
gcpProjectId,
|
|
64970
65040
|
serviceName,
|
|
64971
65041
|
location,
|
|
@@ -64976,7 +65046,7 @@ async function trafficRoutes(app, opts) {
|
|
|
64976
65046
|
firstSync: isFirstSync,
|
|
64977
65047
|
requestUrlSubstrings: [project.canonicalDomain]
|
|
64978
65048
|
});
|
|
64979
|
-
allEvents =
|
|
65049
|
+
allEvents = page2.events;
|
|
64980
65050
|
} catch (e) {
|
|
64981
65051
|
const msg = describeError(e);
|
|
64982
65052
|
markFailed(msg, "PROVIDER_PULL");
|
|
@@ -65055,7 +65125,7 @@ async function trafficRoutes(app, opts) {
|
|
|
65055
65125
|
const collected = [];
|
|
65056
65126
|
let cursor = sourceRow2.lastCursor ?? void 0;
|
|
65057
65127
|
try {
|
|
65058
|
-
for (let
|
|
65128
|
+
for (let page2 = 0; page2 < wpMaxPages; page2 += 1) {
|
|
65059
65129
|
renewWordpressLease();
|
|
65060
65130
|
const pageResult = await pullWordpressEvents({
|
|
65061
65131
|
baseUrl: credential.baseUrl,
|
|
@@ -65599,7 +65669,7 @@ async function trafficRoutes(app, opts) {
|
|
|
65599
65669
|
pullErrorPrefix = "Cloud Run pull failed";
|
|
65600
65670
|
pullForBackfill = async () => {
|
|
65601
65671
|
const accessToken = await resolveAccessToken2(credential);
|
|
65602
|
-
const
|
|
65672
|
+
const page2 = await pullEvents(accessToken, {
|
|
65603
65673
|
gcpProjectId,
|
|
65604
65674
|
serviceName,
|
|
65605
65675
|
location,
|
|
@@ -65615,7 +65685,7 @@ async function trafficRoutes(app, opts) {
|
|
|
65615
65685
|
orderBy: "timestamp asc",
|
|
65616
65686
|
requestUrlSubstrings: [project.canonicalDomain]
|
|
65617
65687
|
});
|
|
65618
|
-
return
|
|
65688
|
+
return page2.events;
|
|
65619
65689
|
};
|
|
65620
65690
|
} else {
|
|
65621
65691
|
const credentialStore = opts.vercelTrafficCredentialStore;
|
|
@@ -71982,12 +72052,12 @@ function readSiteAuditIssues(input) {
|
|
|
71982
72052
|
snapshot.detailsAvailable,
|
|
71983
72053
|
issueId ?? null
|
|
71984
72054
|
])).update(crossJson);
|
|
71985
|
-
const addMember = (group,
|
|
72055
|
+
const addMember = (group, page2) => {
|
|
71986
72056
|
group.affectedPages += 1;
|
|
71987
|
-
if (group.examples.length < 3) group.examples.push(
|
|
72057
|
+
if (group.examples.length < 3) group.examples.push(page2);
|
|
71988
72058
|
else group.examplesTruncated = true;
|
|
71989
72059
|
if (group.id === issueId) {
|
|
71990
|
-
if (selectedMembers >= offset && members.length < limit + 1) members.push(
|
|
72060
|
+
if (selectedMembers >= offset && members.length < limit + 1) members.push(page2);
|
|
71991
72061
|
selectedMembers += 1;
|
|
71992
72062
|
}
|
|
71993
72063
|
};
|
|
@@ -72040,12 +72110,12 @@ function readSiteAuditIssues(input) {
|
|
|
72040
72110
|
auditScore: siteCrawlPages.auditScore,
|
|
72041
72111
|
auditFields: siteCrawlPages.auditFields
|
|
72042
72112
|
}).from(siteCrawlPages).where(and82(scope, after === void 0 ? void 0 : gt10(siteCrawlPages.nodeKey, after))).orderBy(asc21(siteCrawlPages.nodeKey)).limit(200).all();
|
|
72043
|
-
for (const
|
|
72044
|
-
evidenceHash.update(JSON.stringify(
|
|
72045
|
-
const fields = record(
|
|
72046
|
-
if (
|
|
72113
|
+
for (const page2 of pages) {
|
|
72114
|
+
evidenceHash.update(JSON.stringify(page2));
|
|
72115
|
+
const fields = record(page2.auditFields);
|
|
72116
|
+
if (page2.auditScore !== null || fields?.schemaVersion === "1.0") coverage.auditedPages += 1;
|
|
72047
72117
|
if (fields?.schemaVersion !== "1.0") {
|
|
72048
|
-
if (
|
|
72118
|
+
if (page2.auditScore !== null) coverage.pagesWithoutFindingEvidence += 1;
|
|
72049
72119
|
continue;
|
|
72050
72120
|
}
|
|
72051
72121
|
let pageComplete = Array.isArray(fields.factors) && Array.isArray(fields.criticalDefects);
|
|
@@ -72087,7 +72157,7 @@ function readSiteAuditIssues(input) {
|
|
|
72087
72157
|
examples: [],
|
|
72088
72158
|
examplesTruncated: false
|
|
72089
72159
|
});
|
|
72090
|
-
addMember(group, pageEvidence(
|
|
72160
|
+
addMember(group, pageEvidence(page2.nodeKey, page2.url, finding2.message, factor));
|
|
72091
72161
|
}
|
|
72092
72162
|
}
|
|
72093
72163
|
for (const rawDefect of Array.isArray(fields.criticalDefects) ? fields.criticalDefects : []) {
|
|
@@ -72117,7 +72187,7 @@ function readSiteAuditIssues(input) {
|
|
|
72117
72187
|
});
|
|
72118
72188
|
if (defect.severity === "critical") group.severity = "critical";
|
|
72119
72189
|
addMember(group, {
|
|
72120
|
-
...pageEvidence(
|
|
72190
|
+
...pageEvidence(page2.nodeKey, page2.url, defect.detail),
|
|
72121
72191
|
recommendations: [defect.recommendation.slice(0, 400)],
|
|
72122
72192
|
recommendationsScope: "issue",
|
|
72123
72193
|
recommendationsTruncated: defect.recommendation.length > 400
|
|
@@ -73804,14 +73874,14 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
73804
73874
|
};
|
|
73805
73875
|
const scope = detailScopeFor(project.id, snapshot);
|
|
73806
73876
|
if (!scope) return { state: "details-unavailable", ...provenance };
|
|
73807
|
-
const
|
|
73808
|
-
if (!
|
|
73877
|
+
const page2 = pageInScope(scope, nodeKey ? { nodeKey } : { url });
|
|
73878
|
+
if (!page2) return { state: "not-found", ...provenance };
|
|
73809
73879
|
const identity = {
|
|
73810
|
-
nodeKey:
|
|
73811
|
-
url:
|
|
73812
|
-
auditState:
|
|
73880
|
+
nodeKey: page2.nodeKey,
|
|
73881
|
+
url: page2.url,
|
|
73882
|
+
auditState: page2.auditState
|
|
73813
73883
|
};
|
|
73814
|
-
if (
|
|
73884
|
+
if (page2.auditScore == null) {
|
|
73815
73885
|
return {
|
|
73816
73886
|
state: "not-audited",
|
|
73817
73887
|
...provenance,
|
|
@@ -73825,8 +73895,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
73825
73895
|
state: "ready",
|
|
73826
73896
|
...provenance,
|
|
73827
73897
|
...identity,
|
|
73828
|
-
auditScore:
|
|
73829
|
-
...mapCrawlPageAuditEvidence(
|
|
73898
|
+
auditScore: page2.auditScore,
|
|
73899
|
+
...mapCrawlPageAuditEvidence(page2)
|
|
73830
73900
|
};
|
|
73831
73901
|
});
|
|
73832
73902
|
app.get("/projects/:name/technical-aeo/crawl/pages", async (request) => {
|
|
@@ -73995,9 +74065,9 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
73995
74065
|
const limit = parseBoundedLimit(request.query.limit, 50, 100);
|
|
73996
74066
|
const offset = decodeCursor(request.query.cursor);
|
|
73997
74067
|
const sortedChildren = [...children.entries()].sort(([left], [right]) => left.localeCompare(right));
|
|
73998
|
-
const
|
|
73999
|
-
const hasMore =
|
|
74000
|
-
const visible = hasMore ?
|
|
74068
|
+
const page2 = sortedChildren.slice(offset, offset + limit + 1);
|
|
74069
|
+
const hasMore = page2.length > limit;
|
|
74070
|
+
const visible = hasMore ? page2.slice(0, limit) : page2;
|
|
74001
74071
|
return {
|
|
74002
74072
|
project: project.name,
|
|
74003
74073
|
hasCrawlData: true,
|