@ainyc/canonry 4.186.7 → 4.186.9
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/assets/assets/{AuditHistoryPanel-9q5v4zHj.js → AuditHistoryPanel-aXPOAK7n.js} +1 -1
- package/assets/assets/{BacklinksPage-C2QVWfQf.js → BacklinksPage-Bim-7fNk.js} +1 -1
- package/assets/assets/{HistoryPage-oLCQA7-T.js → HistoryPage-B8RyIjRC.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DUYt5ceA.js → MeasurementPropertyPage-BlxY3qHW.js} +1 -1
- package/assets/assets/ProjectPage-BMZrEjBE.js +9 -0
- package/assets/assets/{RunRow-kaFXI_VP.js → RunRow-B28gp-6g.js} +1 -1
- package/assets/assets/{RunsPage-CQizRJxf.js → RunsPage-BXm6DVdt.js} +1 -1
- package/assets/assets/{SettingsPage-BHh4Y7Qg.js → SettingsPage-CJX7c5HH.js} +1 -1
- package/assets/assets/{SiteHealthSection-DjmPK0Tg.js → SiteHealthSection-Ys8sVumO.js} +3 -3
- package/assets/assets/{TrafficPage-B3N0r5gW.js → TrafficPage-wPdIYn8H.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-C27GkPF4.js → TrafficSourceDetailPage-C813qZsA.js} +1 -1
- package/assets/assets/{extract-error-message-DlmIEdy_.js → extract-error-message-C3RpUAm_.js} +1 -1
- package/assets/assets/{index-DVa1lkiE.js → index-Dr_-IUJz.js} +23 -23
- package/assets/assets/{react-sigma_core.esm.min-BBOzBU_n.js → react-sigma_core.esm.min-LmiGNvR6.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-7CG3QE4N.js → chunk-EMSDPSQM.js} +130 -68
- package/dist/{chunk-CFJHRXZ3.js → chunk-LNBX7RTN.js} +556 -536
- package/dist/{chunk-FGEHMYIW.js → chunk-O26JKJXV.js} +41 -6
- package/dist/{chunk-42P3CXIH.js → chunk-U3M2VALC.js} +20 -3
- package/dist/{chunk-7TYSFZEG.js → chunk-XD2ZD2BP.js} +2 -2
- package/dist/cli.js +5 -5
- package/dist/index.d.ts +8 -0
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-KBHLNDGO.js → intelligence-service-UZGA24EF.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +11 -11
- package/assets/assets/ProjectPage-Dsao_AiN.js +0 -9
package/assets/assets/{react-sigma_core.esm.min-BBOzBU_n.js → react-sigma_core.esm.min-LmiGNvR6.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{g as Bt,t as S,r as C}from"./vendor-tanstack-CYBjbqVr.js";import{e as Ht,G as Wt}from"./SiteHealthSection-
|
|
1
|
+
import{g as Bt,t as S,r as C}from"./vendor-tanstack-CYBjbqVr.js";import{e as Ht,G as Wt}from"./SiteHealthSection-Ys8sVumO.js";import"./index-Dr_-IUJz.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-lucide-BovNTc41.js";import"./vendor-markdown-9tTeP8v7.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-DLEICrrL.js";function Vt(r,n){if(typeof r!="object"||!r)return r;var i=r[Symbol.toPrimitive];if(i!==void 0){var e=i.call(r,n);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function ae(r){var n=Vt(r,"string");return typeof n=="symbol"?n:n+""}function A(r,n){if(!(r instanceof n))throw new TypeError("Cannot call a class as a function")}function He(r,n){for(var i=0;i<n.length;i++){var e=n[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(r,ae(e.key),e)}}function L(r,n,i){return n&&He(r.prototype,n),i&&He(r,i),Object.defineProperty(r,"prototype",{writable:!1}),r}function Q(r){return Q=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},Q(r)}function yt(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(yt=function(){return!!r})()}function jt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function Zt(r,n){if(n&&(typeof n=="object"||typeof n=="function"))return n;if(n!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return jt(r)}function I(r,n,i){return n=Q(n),Zt(r,yt()?Reflect.construct(n,i||[],Q(r).constructor):n.apply(r,i))}function xe(r,n){return xe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i,e){return i.__proto__=e,i},xe(r,n)}function G(r,n){if(typeof n!="function"&&n!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(n&&n.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),n&&xe(r,n)}function qt(r){if(Array.isArray(r))return r}function Yt(r,n){var i=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(i!=null){var e,t,a,o,s=[],l=!0,h=!1;try{if(a=(i=i.call(r)).next,n===0){if(Object(i)!==i)return;l=!1}else for(;!(l=(e=a.call(i)).done)&&(s.push(e.value),s.length!==n);l=!0);}catch(u){h=!0,t=u}finally{try{if(!l&&i.return!=null&&(o=i.return(),Object(o)!==o))return}finally{if(h)throw t}}return s}}function Se(r,n){(n==null||n>r.length)&&(n=r.length);for(var i=0,e=Array(n);i<n;i++)e[i]=r[i];return e}function Tt(r,n){if(r){if(typeof r=="string")return Se(r,n);var i={}.toString.call(r).slice(8,-1);return i==="Object"&&r.constructor&&(i=r.constructor.name),i==="Map"||i==="Set"?Array.from(r):i==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?Se(r,n):void 0}}function Xt(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
|
|
2
2
|
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function ee(r,n){return qt(r)||Yt(r,n)||Tt(r,n)||Xt()}var pe={black:"#000000",silver:"#C0C0C0",gray:"#808080",grey:"#808080",white:"#FFFFFF",maroon:"#800000",red:"#FF0000",purple:"#800080",fuchsia:"#FF00FF",green:"#008000",lime:"#00FF00",olive:"#808000",yellow:"#FFFF00",navy:"#000080",blue:"#0000FF",teal:"#008080",aqua:"#00FFFF",darkblue:"#00008B",mediumblue:"#0000CD",darkgreen:"#006400",darkcyan:"#008B8B",deepskyblue:"#00BFFF",darkturquoise:"#00CED1",mediumspringgreen:"#00FA9A",springgreen:"#00FF7F",cyan:"#00FFFF",midnightblue:"#191970",dodgerblue:"#1E90FF",lightseagreen:"#20B2AA",forestgreen:"#228B22",seagreen:"#2E8B57",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",limegreen:"#32CD32",mediumseagreen:"#3CB371",turquoise:"#40E0D0",royalblue:"#4169E1",steelblue:"#4682B4",darkslateblue:"#483D8B",mediumturquoise:"#48D1CC",indigo:"#4B0082",darkolivegreen:"#556B2F",cadetblue:"#5F9EA0",cornflowerblue:"#6495ED",rebeccapurple:"#663399",mediumaquamarine:"#66CDAA",dimgray:"#696969",dimgrey:"#696969",slateblue:"#6A5ACD",olivedrab:"#6B8E23",slategray:"#708090",slategrey:"#708090",lightslategray:"#778899",lightslategrey:"#778899",mediumslateblue:"#7B68EE",lawngreen:"#7CFC00",chartreuse:"#7FFF00",aquamarine:"#7FFFD4",skyblue:"#87CEEB",lightskyblue:"#87CEFA",blueviolet:"#8A2BE2",darkred:"#8B0000",darkmagenta:"#8B008B",saddlebrown:"#8B4513",darkseagreen:"#8FBC8F",lightgreen:"#90EE90",mediumpurple:"#9370DB",darkviolet:"#9400D3",palegreen:"#98FB98",darkorchid:"#9932CC",yellowgreen:"#9ACD32",sienna:"#A0522D",brown:"#A52A2A",darkgray:"#A9A9A9",darkgrey:"#A9A9A9",lightblue:"#ADD8E6",greenyellow:"#ADFF2F",paleturquoise:"#AFEEEE",lightsteelblue:"#B0C4DE",powderblue:"#B0E0E6",firebrick:"#B22222",darkgoldenrod:"#B8860B",mediumorchid:"#BA55D3",rosybrown:"#BC8F8F",darkkhaki:"#BDB76B",mediumvioletred:"#C71585",indianred:"#CD5C5C",peru:"#CD853F",chocolate:"#D2691E",tan:"#D2B48C",lightgray:"#D3D3D3",lightgrey:"#D3D3D3",thistle:"#D8BFD8",orchid:"#DA70D6",goldenrod:"#DAA520",palevioletred:"#DB7093",crimson:"#DC143C",gainsboro:"#DCDCDC",plum:"#DDA0DD",burlywood:"#DEB887",lightcyan:"#E0FFFF",lavender:"#E6E6FA",darksalmon:"#E9967A",violet:"#EE82EE",palegoldenrod:"#EEE8AA",lightcoral:"#F08080",khaki:"#F0E68C",aliceblue:"#F0F8FF",honeydew:"#F0FFF0",azure:"#F0FFFF",sandybrown:"#F4A460",wheat:"#F5DEB3",beige:"#F5F5DC",whitesmoke:"#F5F5F5",mintcream:"#F5FFFA",ghostwhite:"#F8F8FF",salmon:"#FA8072",antiquewhite:"#FAEBD7",linen:"#FAF0E6",lightgoldenrodyellow:"#FAFAD2",oldlace:"#FDF5E6",magenta:"#FF00FF",deeppink:"#FF1493",orangered:"#FF4500",tomato:"#FF6347",hotpink:"#FF69B4",coral:"#FF7F50",darkorange:"#FF8C00",lightsalmon:"#FFA07A",orange:"#FFA500",lightpink:"#FFB6C1",pink:"#FFC0CB",gold:"#FFD700",peachpuff:"#FFDAB9",navajowhite:"#FFDEAD",moccasin:"#FFE4B5",bisque:"#FFE4C4",mistyrose:"#FFE4E1",blanchedalmond:"#FFEBCD",papayawhip:"#FFEFD5",lavenderblush:"#FFF0F5",seashell:"#FFF5EE",cornsilk:"#FFF8DC",lemonchiffon:"#FFFACD",floralwhite:"#FFFAF0",snow:"#FFFAFA",lightyellow:"#FFFFE0",ivory:"#FFFFF0"},Ct=new Int8Array(4),be=new Int32Array(Ct.buffer,0,1),$t=new Float32Array(Ct.buffer,0,1),Kt=/^\s*rgba?\s*\(/,Jt=/^\s*rgba?\s*\(\s*([0-9]*)\s*,\s*([0-9]*)\s*,\s*([0-9]*)(?:\s*,\s*(.*)?)?\)\s*$/;function Qt(r){var n=0,i=0,e=0,t=1;if(r[0]==="#")r.length===4?(n=parseInt(r.charAt(1)+r.charAt(1),16),i=parseInt(r.charAt(2)+r.charAt(2),16),e=parseInt(r.charAt(3)+r.charAt(3),16)):(n=parseInt(r.charAt(1)+r.charAt(2),16),i=parseInt(r.charAt(3)+r.charAt(4),16),e=parseInt(r.charAt(5)+r.charAt(6),16)),r.length===9&&(t=parseInt(r.charAt(7)+r.charAt(8),16)/255);else if(Kt.test(r)){var a=r.match(Jt);a&&(n=+a[1],i=+a[2],e=+a[3],a[4]&&(t=+a[4]))}return{r:n,g:i,b:e,a:t}}var J={};for(var le in pe)J[le]=oe(pe[le]),J[pe[le]]=J[le];function Rt(r,n,i,e,t){return be[0]=e<<24|i<<16|n<<8|r,be[0]=be[0]&4278190079,$t[0]}function oe(r){if(r=r.toLowerCase(),typeof J[r]<"u")return J[r];var n=Qt(r),i=n.r,e=n.g,t=n.b,a=n.a;a=a*255|0;var o=Rt(i,e,t,a);return J[r]=o,o}var Ee={};function _t(r){if(typeof Ee[r]<"u")return Ee[r];var n=(r&16711680)>>>16,i=(r&65280)>>>8,e=r&255,t=255,a=Rt(n,i,e,t);return Ee[r]=a,a}function We(r,n,i,e){return i+(n<<8)+(r<<16)}function Ve(r,n,i,e,t,a){var o=Math.floor(i/a*t),s=Math.floor(r.drawingBufferHeight/a-e/a*t),l=new Uint8Array(4);r.bindFramebuffer(r.FRAMEBUFFER,n),r.readPixels(o,s,1,1,r.RGBA,r.UNSIGNED_BYTE,l);var h=ee(l,4),u=h[0],d=h[1],f=h[2],g=h[3];return[u,d,f,g]}function c(r,n,i){return(n=ae(n))in r?Object.defineProperty(r,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):r[n]=i,r}function je(r,n){var i=Object.keys(r);if(Object.getOwnPropertySymbols){var e=Object.getOwnPropertySymbols(r);n&&(e=e.filter(function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable})),i.push.apply(i,e)}return i}function b(r){for(var n=1;n<arguments.length;n++){var i=arguments[n]!=null?arguments[n]:{};n%2?je(Object(i),!0).forEach(function(e){c(r,e,i[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(i)):je(Object(i)).forEach(function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(i,e))})}return r}function ei(r,n){for(;!{}.hasOwnProperty.call(r,n)&&(r=Q(r))!==null;);return r}function Ae(){return Ae=typeof Reflect<"u"&&Reflect.get?Reflect.get.bind():function(r,n,i){var e=ei(r,n);if(e){var t=Object.getOwnPropertyDescriptor(e,n);return t.get?t.get.call(arguments.length<3?r:i):t.value}},Ae.apply(null,arguments)}function wt(r,n,i,e){var t=Ae(Q(r.prototype),n,i);return typeof t=="function"?function(a){return t.apply(i,a)}:t}function ti(r){return r.normalized?1:r.size}function ye(r){var n=0;return r.forEach(function(i){return n+=ti(i)}),n}function xt(r,n,i){var e=r==="VERTEX"?n.VERTEX_SHADER:n.FRAGMENT_SHADER,t=n.createShader(e);if(t===null)throw new Error("loadShader: error while creating the shader");n.shaderSource(t,i),n.compileShader(t);var a=n.getShaderParameter(t,n.COMPILE_STATUS);if(!a){var o=n.getShaderInfoLog(t);throw n.deleteShader(t),new Error(`loadShader: error while compiling the shader:
|
|
3
3
|
`.concat(o,`
|
|
4
4
|
`).concat(i))}return t}function ii(r,n){return xt("VERTEX",r,n)}function ri(r,n){return xt("FRAGMENT",r,n)}function ni(r,n){var i=r.createProgram();if(i===null)throw new Error("loadProgram: error while creating the program.");var e,t;for(e=0,t=n.length;e<t;e++)r.attachShader(i,n[e]);r.linkProgram(i);var a=r.getProgramParameter(i,r.LINK_STATUS);if(!a){var o=r.getProgramInfoLog(i);throw r.deleteProgram(i),new Error("loadProgram: error while linking the program: ".concat(o))}return i}function Ze(r){var n=r.gl,i=r.buffer,e=r.program,t=r.vertexShader,a=r.fragmentShader;n.deleteShader(t),n.deleteShader(a),n.deleteProgram(e),n.deleteBuffer(i)}var qe=`#define PICKING_MODE
|
package/assets/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
13
13
|
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />
|
|
14
14
|
<title>Canonry</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-Dr_-IUJz.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-CYBjbqVr.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-BpmvLvpp.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-FA0uySU7.js">
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
DEFAULT_DISCOVERY_PROMOTE_BUCKETS,
|
|
48
48
|
DEFAULT_DISCOVERY_PROMOTE_COMPETITOR_TYPES,
|
|
49
49
|
DEFAULT_MEASUREMENT_CONFIG,
|
|
50
|
+
DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT,
|
|
50
51
|
DISCOVERY_DEFAULT_DEDUP_THRESHOLD,
|
|
51
52
|
DISCOVERY_DEFAULT_PROBE_CONCURRENCY,
|
|
52
53
|
DISCOVERY_PROBE_CONCURRENCY_CAP,
|
|
@@ -553,6 +554,7 @@ import {
|
|
|
553
554
|
reportConfidenceLabel,
|
|
554
555
|
reportHorizonLabel,
|
|
555
556
|
reportSeverityLabel,
|
|
557
|
+
researchDailyLimitExceeded,
|
|
556
558
|
researchRunCreateSchema,
|
|
557
559
|
researchRunDetailSchema,
|
|
558
560
|
researchRunListSchema,
|
|
@@ -666,10 +668,10 @@ import {
|
|
|
666
668
|
wordpressSchemaDeployResultDtoSchema,
|
|
667
669
|
wordpressSchemaStatusResultDtoSchema,
|
|
668
670
|
wordpressStatusDtoSchema
|
|
669
|
-
} from "./chunk-
|
|
671
|
+
} from "./chunk-LNBX7RTN.js";
|
|
670
672
|
|
|
671
673
|
// src/intelligence-service.ts
|
|
672
|
-
import { eq as eq67, desc as desc29, asc as asc12, and as and56, ne as ne10, or as or14, inArray as inArray25, gte as
|
|
674
|
+
import { eq as eq67, desc as desc29, asc as asc12, and as and56, ne as ne10, or as or14, inArray as inArray25, gte as gte18, lte as lte15, isNull as isNull12, sql as sql26, exists } from "drizzle-orm";
|
|
673
675
|
|
|
674
676
|
// ../db/src/client.ts
|
|
675
677
|
import { mkdirSync } from "fs";
|
|
@@ -2722,6 +2724,7 @@ var researchRuns = sqliteTable("research_runs", {
|
|
|
2722
2724
|
idempotencyKey: text("idempotency_key"),
|
|
2723
2725
|
requestHash: text("request_hash"),
|
|
2724
2726
|
error: text("error"),
|
|
2727
|
+
initiatedBy: text("initiated_by", { mode: "json" }).$type(),
|
|
2725
2728
|
startedAt: text("started_at"),
|
|
2726
2729
|
finishedAt: text("finished_at"),
|
|
2727
2730
|
createdAt: text("created_at").notNull()
|
|
@@ -7139,6 +7142,13 @@ var MIGRATION_VERSIONS = [
|
|
|
7139
7142
|
SELECT RAISE(ABORT, 'simple measurement definition is immutable');
|
|
7140
7143
|
END`
|
|
7141
7144
|
]
|
|
7145
|
+
},
|
|
7146
|
+
{
|
|
7147
|
+
version: 151,
|
|
7148
|
+
name: "research-run-principal-attribution",
|
|
7149
|
+
statements: [
|
|
7150
|
+
`ALTER TABLE research_runs ADD COLUMN initiated_by TEXT`
|
|
7151
|
+
]
|
|
7142
7152
|
}
|
|
7143
7153
|
];
|
|
7144
7154
|
function addRunsMeasurementPlanVersionForeignKey(tx) {
|
|
@@ -9169,15 +9179,15 @@ function buildAiSourceOrigin(snapshots, projectDomains, competitorDomains, topDo
|
|
|
9169
9179
|
totalCitations++;
|
|
9170
9180
|
}
|
|
9171
9181
|
}
|
|
9172
|
-
const categories = [...categoryCounts.entries()].map(([category, { label, count:
|
|
9182
|
+
const categories = [...categoryCounts.entries()].map(([category, { label, count: count3 }]) => ({
|
|
9173
9183
|
category,
|
|
9174
9184
|
label,
|
|
9175
|
-
count:
|
|
9176
|
-
sharePct: totalCitations > 0 ? Math.round(
|
|
9185
|
+
count: count3,
|
|
9186
|
+
sharePct: totalCitations > 0 ? Math.round(count3 / totalCitations * 100) : 0
|
|
9177
9187
|
})).sort((a, b) => b.count - a.count);
|
|
9178
|
-
const topDomains = [...domainCounts.entries()].map(([domain,
|
|
9188
|
+
const topDomains = [...domainCounts.entries()].map(([domain, count3]) => ({
|
|
9179
9189
|
domain,
|
|
9180
|
-
count:
|
|
9190
|
+
count: count3,
|
|
9181
9191
|
isCompetitor: citedDomainBelongsToProject(domain, competitorDomains)
|
|
9182
9192
|
})).sort((a, b) => b.count - a.count).slice(0, topDomainsLimit);
|
|
9183
9193
|
return { categories, topDomains };
|
|
@@ -10771,6 +10781,9 @@ function principalScopes(request) {
|
|
|
10771
10781
|
function isReadSemanticRoute(request) {
|
|
10772
10782
|
return request.routeOptions.config.readSemantic === true;
|
|
10773
10783
|
}
|
|
10784
|
+
function isPaidReadRoute(request) {
|
|
10785
|
+
return request.routeOptions.config.paidRead === true;
|
|
10786
|
+
}
|
|
10774
10787
|
function isTransportEnvelopeRoute(request) {
|
|
10775
10788
|
return request.routeOptions.config.transportEnvelope === true;
|
|
10776
10789
|
}
|
|
@@ -10800,6 +10813,17 @@ function requirePaidReadScope(request) {
|
|
|
10800
10813
|
throw forbidden("This API key was not granted access to OpenAI Ads paid reads.");
|
|
10801
10814
|
}
|
|
10802
10815
|
}
|
|
10816
|
+
function requireResearchGrant(request, allowViewers) {
|
|
10817
|
+
const principal = request.principal;
|
|
10818
|
+
if (!principal) return;
|
|
10819
|
+
if (principal.kind === "api-key") {
|
|
10820
|
+
if (principal.scopes.includes(WILDCARD_SCOPE)) return;
|
|
10821
|
+
throw forbidden("This API key was not granted access to paid research queries.");
|
|
10822
|
+
}
|
|
10823
|
+
if (principal.role === UserRoles.admin) return;
|
|
10824
|
+
if (principal.role === UserRoles.viewer && allowViewers) return;
|
|
10825
|
+
throw forbidden("Research queries are not enabled for viewer accounts on this deployment.");
|
|
10826
|
+
}
|
|
10803
10827
|
function requireBroadInstanceKey(request) {
|
|
10804
10828
|
const principal = request.principal;
|
|
10805
10829
|
if (!principal || principal.kind !== "api-key") return;
|
|
@@ -10959,7 +10983,7 @@ function applyRoleGates(request) {
|
|
|
10959
10983
|
const principal = request.principal;
|
|
10960
10984
|
if (!principal || principal.kind !== "user") return;
|
|
10961
10985
|
request.readSemanticGrant = principal.role === UserRoles.viewer && isReadSemanticRoute(request);
|
|
10962
|
-
if (isReadOnlyKey(principal.scopes) && WRITE_METHODS2.has(request.method) && !request.readSemanticGrant && !isTransportEnvelopeRoute(request)) {
|
|
10986
|
+
if (isReadOnlyKey(principal.scopes) && WRITE_METHODS2.has(request.method) && !request.readSemanticGrant && !isPaidReadRoute(request) && !isTransportEnvelopeRoute(request)) {
|
|
10963
10987
|
throw forbidden(VIEWER_DENIED_MESSAGE);
|
|
10964
10988
|
}
|
|
10965
10989
|
}
|
|
@@ -11995,7 +12019,7 @@ async function projectRoutes(app, opts) {
|
|
|
11995
12019
|
app.get("/projects/:name/delete-preview", async (request, reply) => {
|
|
11996
12020
|
const project = resolveProject(app.db, request.params.name);
|
|
11997
12021
|
const pid = project.id;
|
|
11998
|
-
const
|
|
12022
|
+
const count3 = (n) => n ?? 0;
|
|
11999
12023
|
const queryCount = app.db.select({ n: sql4`count(*)` }).from(queries).where(eq5(queries.projectId, pid)).get();
|
|
12000
12024
|
const competitorCount = app.db.select({ n: sql4`count(*)` }).from(competitors).where(eq5(competitors.projectId, pid)).get();
|
|
12001
12025
|
const runCount = app.db.select({ n: sql4`count(*)` }).from(runs).where(eq5(runs.projectId, pid)).get();
|
|
@@ -12005,14 +12029,14 @@ async function projectRoutes(app, opts) {
|
|
|
12005
12029
|
return reply.send({
|
|
12006
12030
|
project: { id: project.id, name: project.name },
|
|
12007
12031
|
cascadeRows: {
|
|
12008
|
-
queries:
|
|
12009
|
-
competitors:
|
|
12010
|
-
runs:
|
|
12011
|
-
snapshots:
|
|
12012
|
-
insights:
|
|
12032
|
+
queries: count3(queryCount?.n),
|
|
12033
|
+
competitors: count3(competitorCount?.n),
|
|
12034
|
+
runs: count3(runCount?.n),
|
|
12035
|
+
snapshots: count3(snapshotCount?.n),
|
|
12036
|
+
insights: count3(insightCount?.n)
|
|
12013
12037
|
},
|
|
12014
12038
|
detachedRows: {
|
|
12015
|
-
auditLog:
|
|
12039
|
+
auditLog: count3(auditLogCount?.n)
|
|
12016
12040
|
}
|
|
12017
12041
|
});
|
|
12018
12042
|
});
|
|
@@ -12698,14 +12722,14 @@ async function queryRoutes(app, opts) {
|
|
|
12698
12722
|
validProviders: validNames
|
|
12699
12723
|
});
|
|
12700
12724
|
}
|
|
12701
|
-
const
|
|
12725
|
+
const count3 = body.count ?? 5;
|
|
12702
12726
|
if (!opts.onGenerateQueries) {
|
|
12703
12727
|
throw notImplemented("Query generation is not supported in this deployment");
|
|
12704
12728
|
}
|
|
12705
12729
|
const existingRows = app.db.select().from(queries).where(eq8(queries.projectId, project.id)).all();
|
|
12706
12730
|
const existingQueries = existingRows.map((r) => r.query);
|
|
12707
12731
|
try {
|
|
12708
|
-
const generated = await opts.onGenerateQueries(provider,
|
|
12732
|
+
const generated = await opts.onGenerateQueries(provider, count3, {
|
|
12709
12733
|
domain: project.canonicalDomain,
|
|
12710
12734
|
displayName: project.displayName,
|
|
12711
12735
|
country: project.country,
|
|
@@ -12831,14 +12855,14 @@ async function queryRoutes(app, opts) {
|
|
|
12831
12855
|
validProviders: validNames
|
|
12832
12856
|
});
|
|
12833
12857
|
}
|
|
12834
|
-
const
|
|
12858
|
+
const count3 = body.count ?? 5;
|
|
12835
12859
|
if (!opts.onGenerateQueries) {
|
|
12836
12860
|
throw notImplemented("Keyword generation is not supported in this deployment");
|
|
12837
12861
|
}
|
|
12838
12862
|
const existingRows = app.db.select().from(queries).where(eq8(queries.projectId, project.id)).all();
|
|
12839
12863
|
const existingQueries = existingRows.map((r) => r.query);
|
|
12840
12864
|
try {
|
|
12841
|
-
const generated = await opts.onGenerateQueries(provider,
|
|
12865
|
+
const generated = await opts.onGenerateQueries(provider, count3, {
|
|
12842
12866
|
domain: project.canonicalDomain,
|
|
12843
12867
|
displayName: project.displayName,
|
|
12844
12868
|
country: project.country,
|
|
@@ -18682,19 +18706,19 @@ function groupChangesFromRows(rows, identities) {
|
|
|
18682
18706
|
});
|
|
18683
18707
|
}
|
|
18684
18708
|
function countsFromRows(rows, groupChanges) {
|
|
18685
|
-
const
|
|
18686
|
-
const ambiguousRows =
|
|
18687
|
-
const unmatchedRows =
|
|
18688
|
-
const invalidRows =
|
|
18689
|
-
const proposedRows =
|
|
18690
|
-
const excludedRows =
|
|
18709
|
+
const count3 = (status) => rows.filter((row) => row.status === status).length;
|
|
18710
|
+
const ambiguousRows = count3("ambiguous");
|
|
18711
|
+
const unmatchedRows = count3("unmatched");
|
|
18712
|
+
const invalidRows = count3("invalid");
|
|
18713
|
+
const proposedRows = count3("proposed");
|
|
18714
|
+
const excludedRows = count3("excluded");
|
|
18691
18715
|
return {
|
|
18692
18716
|
dataRows: rows.length,
|
|
18693
|
-
matchedRows:
|
|
18717
|
+
matchedRows: count3("matched"),
|
|
18694
18718
|
ambiguousRows,
|
|
18695
18719
|
unmatchedRows,
|
|
18696
18720
|
invalidRows,
|
|
18697
|
-
duplicateRows:
|
|
18721
|
+
duplicateRows: count3("duplicate"),
|
|
18698
18722
|
proposedRows,
|
|
18699
18723
|
excludedRows,
|
|
18700
18724
|
needsAttention: ambiguousRows + unmatchedRows + invalidRows + proposedRows + excludedRows,
|
|
@@ -24056,9 +24080,9 @@ function workloadDiff(before, after) {
|
|
|
24056
24080
|
nextSweepNodes: after.size,
|
|
24057
24081
|
nextSweepProviderCalls: sum(after.values()),
|
|
24058
24082
|
addedNodes: added.length,
|
|
24059
|
-
addedProviderCalls: sum(added.map(([,
|
|
24083
|
+
addedProviderCalls: sum(added.map(([, count3]) => count3)),
|
|
24060
24084
|
removedNodes: removed.length,
|
|
24061
|
-
removedProviderCalls: sum(removed.map(([,
|
|
24085
|
+
removedProviderCalls: sum(removed.map(([, count3]) => count3))
|
|
24062
24086
|
};
|
|
24063
24087
|
}
|
|
24064
24088
|
function candidateDiff(state, nextRows, plan, reusedQueryIds, mutatedQueryIds, scopedRemovalQueryIds) {
|
|
@@ -26201,10 +26225,10 @@ function computeQueryChanges(projectQueries, cutoff) {
|
|
|
26201
26225
|
}
|
|
26202
26226
|
const days = [...byDay.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
26203
26227
|
if (days.length <= 1) return [];
|
|
26204
|
-
return days.slice(1).map(([date,
|
|
26228
|
+
return days.slice(1).map(([date, count3]) => ({
|
|
26205
26229
|
date: (/* @__PURE__ */ new Date(date + "T00:00:00.000Z")).toISOString(),
|
|
26206
|
-
delta:
|
|
26207
|
-
label: `+${
|
|
26230
|
+
delta: count3,
|
|
26231
|
+
label: `+${count3} kp`
|
|
26208
26232
|
}));
|
|
26209
26233
|
}
|
|
26210
26234
|
function pooledRate(buckets, rateKey) {
|
|
@@ -26279,15 +26303,15 @@ function buildRankedList(domains, limit) {
|
|
|
26279
26303
|
function buildCategoryCounts(counts2) {
|
|
26280
26304
|
let grandTotal = 0;
|
|
26281
26305
|
for (const domains of counts2.values()) {
|
|
26282
|
-
for (const
|
|
26306
|
+
for (const count3 of domains.values()) grandTotal += count3;
|
|
26283
26307
|
}
|
|
26284
26308
|
const result = [];
|
|
26285
26309
|
for (const [category, domains] of counts2) {
|
|
26286
26310
|
let categoryTotal = 0;
|
|
26287
26311
|
const domainEntries = [];
|
|
26288
|
-
for (const [domain,
|
|
26289
|
-
categoryTotal +=
|
|
26290
|
-
domainEntries.push({ domain, count:
|
|
26312
|
+
for (const [domain, count3] of domains) {
|
|
26313
|
+
categoryTotal += count3;
|
|
26314
|
+
domainEntries.push({ domain, count: count3 });
|
|
26291
26315
|
}
|
|
26292
26316
|
domainEntries.sort((a, b) => b.count - a.count);
|
|
26293
26317
|
result.push({
|
|
@@ -27563,8 +27587,8 @@ function gscDateRange(report) {
|
|
|
27563
27587
|
const end = summary2?.periodEnd || gsc?.periodEnd || gsc?.trend.at(-1)?.date || "";
|
|
27564
27588
|
return formatDateRange(start, end);
|
|
27565
27589
|
}
|
|
27566
|
-
function pluralize(
|
|
27567
|
-
return
|
|
27590
|
+
function pluralize(count3, singular, plural = `${singular}s`) {
|
|
27591
|
+
return count3 === 1 ? singular : plural;
|
|
27568
27592
|
}
|
|
27569
27593
|
var PROVIDER_DISPLAY_NAMES = {
|
|
27570
27594
|
gemini: "Gemini",
|
|
@@ -29398,9 +29422,9 @@ function renderInsights(report) {
|
|
|
29398
29422
|
);
|
|
29399
29423
|
}
|
|
29400
29424
|
const haveDeduped = list.every((i) => typeof i.instanceCount === "number");
|
|
29401
|
-
const rows = (haveDeduped ? list.map((i) => ({ rep: i, count: i.instanceCount })) : groupInsights(list).map((g) => ({ rep: g.representative, count: g.count }))).map(({ rep: i, count:
|
|
29425
|
+
const rows = (haveDeduped ? list.map((i) => ({ rep: i, count: i.instanceCount })) : groupInsights(list).map((g) => ({ rep: g.representative, count: g.count }))).map(({ rep: i, count: count3 }) => {
|
|
29402
29426
|
const tone = severityTone(i.severity);
|
|
29403
|
-
const countChip =
|
|
29427
|
+
const countChip = count3 > 1 ? ` <span class="badge tone-neutral">\xD7 ${count3}</span>` : "";
|
|
29404
29428
|
return `<tr>
|
|
29405
29429
|
<td class="col-severity"><span class="badge tone-${tone}">${escapeHtml2(reportSeverityLabel(i.severity))}</span></td>
|
|
29406
29430
|
<td class="col-title">${escapeHtml2(i.title)}${countChip}</td>
|
|
@@ -30857,9 +30881,9 @@ function contentActionVerb(action) {
|
|
|
30857
30881
|
return "Add schema to";
|
|
30858
30882
|
}
|
|
30859
30883
|
}
|
|
30860
|
-
function confidenceFromEvidence(
|
|
30861
|
-
if (
|
|
30862
|
-
if (
|
|
30884
|
+
function confidenceFromEvidence(count3) {
|
|
30885
|
+
if (count3 >= 3) return "high";
|
|
30886
|
+
if (count3 >= 1) return "medium";
|
|
30863
30887
|
return "low";
|
|
30864
30888
|
}
|
|
30865
30889
|
function actionAudienceMatches2(action, audience) {
|
|
@@ -32033,9 +32057,9 @@ function summarizeVerificationHits(rows) {
|
|
|
32033
32057
|
return { counts: counts2, unsupportedRows, unsupportedHits };
|
|
32034
32058
|
}
|
|
32035
32059
|
function summarizeServer(crawlers, fetches, referrals) {
|
|
32036
|
-
const total = referrals.reduce((
|
|
32037
|
-
const paid = referrals.reduce((
|
|
32038
|
-
const organic = referrals.reduce((
|
|
32060
|
+
const total = referrals.reduce((count3, row) => count3 + row.sessionsOrHits, 0);
|
|
32061
|
+
const paid = referrals.reduce((count3, row) => count3 + row.paidSessionsOrHits, 0);
|
|
32062
|
+
const organic = referrals.reduce((count3, row) => count3 + row.organicSessionsOrHits, 0);
|
|
32039
32063
|
const crawlerHits = summarizeVerificationHits(crawlers);
|
|
32040
32064
|
const userFetchHits = summarizeVerificationHits(fetches);
|
|
32041
32065
|
return {
|
|
@@ -32184,10 +32208,10 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32184
32208
|
const gaWindow = gaStartDate && gaEndDate ? gaRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
32185
32209
|
const legacyGaCohorts = gaCohorts.map((cohort) => ({
|
|
32186
32210
|
...cohort,
|
|
32187
|
-
organicSessions: gaRows.filter((row) => inRange(row.date, cohort.startDate, cohort.endDate)).reduce((
|
|
32211
|
+
organicSessions: gaRows.filter((row) => inRange(row.date, cohort.startDate, cohort.endDate)).reduce((count3, row) => count3 + row.organicSessions, 0)
|
|
32188
32212
|
}));
|
|
32189
32213
|
let ga4 = gaRows.length ? {
|
|
32190
|
-
organicSessions: gaWindow.reduce((
|
|
32214
|
+
organicSessions: gaWindow.reduce((count3, row) => count3 + row.organicSessions, 0),
|
|
32191
32215
|
cohorts: legacyGaCohorts
|
|
32192
32216
|
} : null;
|
|
32193
32217
|
if (nativeAcquisitionActive && nativeAcquisition.periods.length === 0) {
|
|
@@ -32210,8 +32234,8 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32210
32234
|
const allGaAiRows = db.select().from(gaAiReferrals).where(and30(eq35(gaAiReferrals.projectId, project.id), gte10(gaAiReferrals.date, gaStartDate ?? startDate), lte8(gaAiReferrals.date, gaEndDate ?? endDate))).all().filter((row) => row.sourceDimension === "session");
|
|
32211
32235
|
const aiRows = gaStartDate && gaEndDate ? allGaAiRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
32212
32236
|
const gaAiReferralSummary = allGaAiRows.length ? {
|
|
32213
|
-
paidSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.paid).reduce((
|
|
32214
|
-
organicSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.organic).reduce((
|
|
32237
|
+
paidSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.paid).reduce((count3, row) => count3 + row.sessions, 0),
|
|
32238
|
+
organicSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.organic).reduce((count3, row) => count3 + row.sessions, 0)
|
|
32215
32239
|
} : null;
|
|
32216
32240
|
const serverSources = db.select().from(trafficSources).where(eq35(trafficSources.projectId, project.id)).all();
|
|
32217
32241
|
const serverStart = `${startDate}T00:00:00`;
|
|
@@ -35937,11 +35961,11 @@ var routeCatalog = [
|
|
|
35937
35961
|
method: "post",
|
|
35938
35962
|
path: "/api/v1/projects/{name}/research/runs",
|
|
35939
35963
|
summary: "Start an isolated research query batch",
|
|
35940
|
-
description: "Runs one to fifty ad-hoc queries through one API provider and saves the answer evidence. Research never creates tracked queries, shared runs, snapshots, insights, or notifications.",
|
|
35964
|
+
description: "Runs one to fifty ad-hoc queries through one API provider and saves the answer evidence. Research never creates tracked queries, shared runs, snapshots, insights, or notifications. Administrators are always allowed; signed-in viewers require the deployment opt-in and a per-project daily allowance. Read-only and narrowly scoped API keys are refused.",
|
|
35941
35965
|
tags: ["research"],
|
|
35942
35966
|
parameters: [nameParameter],
|
|
35943
35967
|
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ResearchRunCreate" } } } },
|
|
35944
|
-
responses: { 200: jsonResponse("Idempotent request returned its existing research run.", "ResearchRunDetailDto"), 202: jsonResponse("Research batch queued.", "ResearchRunDetailDto"), 400: errorResponse("Invalid provider, model, location, or request."), 404: errorResponse("Project not found."), 409: errorResponse("Idempotency key was reused with a different payload."), 422: errorResponse("Research executor is unavailable on this deployment.") }
|
|
35968
|
+
responses: { 200: jsonResponse("Idempotent request returned its existing research run.", "ResearchRunDetailDto"), 202: jsonResponse("Research batch queued.", "ResearchRunDetailDto"), 400: errorResponse("Invalid provider, model, location, or request."), 403: errorResponse("Paid research was not granted to this principal."), 404: errorResponse("Project not found."), 409: errorResponse("Idempotency key was reused with a different payload."), 422: errorResponse("Research executor is unavailable on this deployment."), 429: errorResponse("The viewer reached the per-project UTC-day research limit.") }
|
|
35945
35969
|
},
|
|
35946
35970
|
{
|
|
35947
35971
|
method: "get",
|
|
@@ -44402,12 +44426,12 @@ async function getLodging(accessToken, locationName, opts = {}) {
|
|
|
44402
44426
|
}
|
|
44403
44427
|
}
|
|
44404
44428
|
function countPopulatedGroups(lodging) {
|
|
44405
|
-
let
|
|
44429
|
+
let count3 = 0;
|
|
44406
44430
|
for (const [key, value] of Object.entries(lodging)) {
|
|
44407
44431
|
if (key === "name" || key === "metadata") continue;
|
|
44408
|
-
if (isPopulated(value))
|
|
44432
|
+
if (isPopulated(value)) count3++;
|
|
44409
44433
|
}
|
|
44410
|
-
return
|
|
44434
|
+
return count3;
|
|
44411
44435
|
}
|
|
44412
44436
|
function isPopulated(value) {
|
|
44413
44437
|
if (value === null || value === void 0) return false;
|
|
@@ -49451,7 +49475,7 @@ function createActivationStore(app, request) {
|
|
|
49451
49475
|
function countManifest(manifest) {
|
|
49452
49476
|
return {
|
|
49453
49477
|
adGroupCount: manifest.campaign.adGroups.length,
|
|
49454
|
-
adCount: manifest.campaign.adGroups.reduce((
|
|
49478
|
+
adCount: manifest.campaign.adGroups.reduce((count3, group) => count3 + group.ads.length, 0)
|
|
49455
49479
|
};
|
|
49456
49480
|
}
|
|
49457
49481
|
function resolveAdsActivationMaxEntities(env = process.env) {
|
|
@@ -56734,7 +56758,7 @@ async function queryBacklinks(opts) {
|
|
|
56734
56758
|
const reversed = opts.targets.map(reverseDomain);
|
|
56735
56759
|
const targetList = reversed.map(quote).join(", ");
|
|
56736
56760
|
const limitClause = opts.limitPerTarget ? `QUALIFY row_number() OVER (PARTITION BY t.target_rev_domain ORDER BY v.num_hosts DESC) <= ${Math.floor(opts.limitPerTarget)}` : "";
|
|
56737
|
-
const
|
|
56761
|
+
const sql27 = `
|
|
56738
56762
|
WITH vertices AS (
|
|
56739
56763
|
SELECT * FROM read_csv(
|
|
56740
56764
|
${quote(opts.vertexPath)},
|
|
@@ -56770,7 +56794,7 @@ async function queryBacklinks(opts) {
|
|
|
56770
56794
|
const conn = await instance.connect();
|
|
56771
56795
|
let rows;
|
|
56772
56796
|
try {
|
|
56773
|
-
const reader = await conn.runAndReadAll(
|
|
56797
|
+
const reader = await conn.runAndReadAll(sql27);
|
|
56774
56798
|
rows = reader.getRowObjects();
|
|
56775
56799
|
} finally {
|
|
56776
56800
|
conn.disconnectSync?.();
|
|
@@ -82860,10 +82884,17 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82860
82884
|
|
|
82861
82885
|
// ../api-routes/src/research.ts
|
|
82862
82886
|
import crypto49 from "crypto";
|
|
82863
|
-
import { and as and54, desc as desc28, eq as eq65 } from "drizzle-orm";
|
|
82887
|
+
import { and as and54, count as count2, desc as desc28, eq as eq65, gte as gte17, lt as lt11, sql as sql25 } from "drizzle-orm";
|
|
82864
82888
|
var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
|
|
82865
82889
|
async function researchRoutes(app, opts) {
|
|
82866
|
-
|
|
82890
|
+
const viewerDailyRunLimit = opts.viewerDailyRunLimit ?? DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT;
|
|
82891
|
+
if (!Number.isInteger(viewerDailyRunLimit) || viewerDailyRunLimit <= 0) {
|
|
82892
|
+
throw new Error("viewerDailyRunLimit must be a positive integer");
|
|
82893
|
+
}
|
|
82894
|
+
app.post("/projects/:name/research/runs", {
|
|
82895
|
+
config: { paidRead: true }
|
|
82896
|
+
}, async (request, reply) => {
|
|
82897
|
+
requireResearchGrant(request, opts.allowViewers ?? false);
|
|
82867
82898
|
const project = resolveProject(app.db, request.params.name);
|
|
82868
82899
|
if (!opts.onResearchRunRequested) throw missingDependency("Research execution is not available on this deployment.", { reason: "no-research-handler" });
|
|
82869
82900
|
const parsed = researchRunCreateSchema.safeParse(request.body ?? {});
|
|
@@ -82888,6 +82919,7 @@ async function researchRoutes(app, opts) {
|
|
|
82888
82919
|
const normalized = { queries: input.queries, provider: providerName, model: requestedModel2, location: location ?? null };
|
|
82889
82920
|
const requestHash2 = crypto49.createHash("sha256").update(JSON.stringify(normalized)).digest("hex");
|
|
82890
82921
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
82922
|
+
const initiatedBy = researchPrincipal(request);
|
|
82891
82923
|
const decision = app.db.transaction((tx) => {
|
|
82892
82924
|
if (input.idempotencyKey) {
|
|
82893
82925
|
const existing = tx.select().from(researchRuns).where(and54(eq65(researchRuns.projectId, project.id), eq65(researchRuns.idempotencyKey, input.idempotencyKey))).get();
|
|
@@ -82896,10 +82928,22 @@ async function researchRoutes(app, opts) {
|
|
|
82896
82928
|
return { reused: true, id: existing.id, shouldDispatch: existing.status === ResearchRunStatuses.queued };
|
|
82897
82929
|
}
|
|
82898
82930
|
}
|
|
82931
|
+
if (initiatedBy?.kind === "user" && initiatedBy.role === UserRoles.viewer) {
|
|
82932
|
+
const { start, end, date } = utcDayBounds(now);
|
|
82933
|
+
const used = tx.select({ value: count2() }).from(researchRuns).where(and54(
|
|
82934
|
+
eq65(researchRuns.projectId, project.id),
|
|
82935
|
+
gte17(researchRuns.createdAt, start),
|
|
82936
|
+
lt11(researchRuns.createdAt, end),
|
|
82937
|
+
sql25`json_extract(${researchRuns.initiatedBy}, '$.role') = ${UserRoles.viewer}`
|
|
82938
|
+
)).get()?.value ?? 0;
|
|
82939
|
+
if (used >= viewerDailyRunLimit) {
|
|
82940
|
+
throw researchDailyLimitExceeded(project.name, viewerDailyRunLimit, date);
|
|
82941
|
+
}
|
|
82942
|
+
}
|
|
82899
82943
|
const id = crypto49.randomUUID();
|
|
82900
|
-
tx.insert(researchRuns).values({ id, projectId: project.id, status: ResearchRunStatuses.queued, provider: providerName, requestedModel: requestedModel2, resolvedModel, location: location ?? null, totalQueries: input.queries.length, idempotencyKey: input.idempotencyKey ?? null, requestHash: input.idempotencyKey ? requestHash2 : null, createdAt: now }).run();
|
|
82944
|
+
tx.insert(researchRuns).values({ id, projectId: project.id, status: ResearchRunStatuses.queued, provider: providerName, requestedModel: requestedModel2, resolvedModel, location: location ?? null, totalQueries: input.queries.length, idempotencyKey: input.idempotencyKey ?? null, requestHash: input.idempotencyKey ? requestHash2 : null, initiatedBy, createdAt: now }).run();
|
|
82901
82945
|
for (const [position, query] of input.queries.entries()) tx.insert(researchRunQueries).values({ id: crypto49.randomUUID(), researchRunId: id, position, queryText: query, status: ResearchQueryStatuses.queued, requestedModel: requestedModel2, resolvedModel, groundingSources: [], citedDomains: [], searchQueries: [], createdAt: now }).run();
|
|
82902
|
-
writeAuditLog(tx, { projectId: project.id, actor: "api", action: "research.created", entityType: "research_run", entityId: id });
|
|
82946
|
+
writeAuditLog(tx, { projectId: project.id, actor: initiatedBy ? `${initiatedBy.kind}:${initiatedBy.id}` : "api", action: "research.created", entityType: "research_run", entityId: id });
|
|
82903
82947
|
return { reused: false, id, shouldDispatch: true };
|
|
82904
82948
|
});
|
|
82905
82949
|
const result = getDetail(app, project.id, decision.id);
|
|
@@ -82926,11 +82970,27 @@ function getDetail(app, projectId, id) {
|
|
|
82926
82970
|
return { ...serializeRun(row), queries: queries2 };
|
|
82927
82971
|
}
|
|
82928
82972
|
function serializeRun(row) {
|
|
82929
|
-
return { id: row.id, projectId: row.projectId, status: row.status, provider: row.provider, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, location: row.location ?? null, totalQueries: row.totalQueries, completedQueries: row.completedQueries, failedQueries: row.failedQueries, error: row.error, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
|
|
82973
|
+
return { id: row.id, projectId: row.projectId, status: row.status, provider: row.provider, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, location: row.location ?? null, totalQueries: row.totalQueries, completedQueries: row.completedQueries, failedQueries: row.failedQueries, error: row.error, initiatedBy: row.initiatedBy ?? null, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
|
|
82930
82974
|
}
|
|
82931
82975
|
function serializeQuery(row) {
|
|
82932
82976
|
return { id: row.id, position: row.position, query: row.queryText, status: row.status, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, servedModel: row.servedModel, answerText: row.answerText, groundingSources: row.groundingSources, citedDomains: row.citedDomains, searchQueries: row.searchQueries, namedCompetitors: row.namedCompetitors, citedCompetitorDomains: row.citedCompetitorDomains, answerMentioned: row.answerMentioned, citationState: row.citationState, error: row.error, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
|
|
82933
82977
|
}
|
|
82978
|
+
function researchPrincipal(request) {
|
|
82979
|
+
const principal = request.principal;
|
|
82980
|
+
if (!principal) return null;
|
|
82981
|
+
return {
|
|
82982
|
+
kind: principal.kind,
|
|
82983
|
+
id: principal.id,
|
|
82984
|
+
name: principal.name,
|
|
82985
|
+
role: principal.kind === "user" ? principal.role ?? null : null
|
|
82986
|
+
};
|
|
82987
|
+
}
|
|
82988
|
+
function utcDayBounds(now) {
|
|
82989
|
+
const date = now.slice(0, 10);
|
|
82990
|
+
const start = `${date}T00:00:00.000Z`;
|
|
82991
|
+
const end = new Date(Date.parse(start) + 24 * 60 * 60 * 1e3).toISOString();
|
|
82992
|
+
return { start, end, date };
|
|
82993
|
+
}
|
|
82934
82994
|
|
|
82935
82995
|
// ../api-routes/src/simple-measurement-definitions.ts
|
|
82936
82996
|
import crypto50 from "crypto";
|
|
@@ -83263,7 +83323,9 @@ async function apiRoutes(app, opts) {
|
|
|
83263
83323
|
await api.register(researchRoutes, {
|
|
83264
83324
|
providerAdapters: opts.providerAdapters,
|
|
83265
83325
|
configuredProviderNames: opts.providerSummary?.filter((provider) => provider.configured).map((provider) => provider.name),
|
|
83266
|
-
onResearchRunRequested: opts.onResearchRunRequested
|
|
83326
|
+
onResearchRunRequested: opts.onResearchRunRequested,
|
|
83327
|
+
allowViewers: opts.researchAllowViewers,
|
|
83328
|
+
viewerDailyRunLimit: opts.researchViewerDailyRunLimit
|
|
83267
83329
|
});
|
|
83268
83330
|
await api.register(technicalAeoRoutes, {
|
|
83269
83331
|
onSiteAuditRequested: opts.onSiteAuditRequested
|
|
@@ -83694,7 +83756,7 @@ function matchesBrandAlias(candidate, aliases) {
|
|
|
83694
83756
|
var RECURRENCE_LOOKBACK_RUNS = 5;
|
|
83695
83757
|
var HISTORY_WINDOW_RUNS = Math.max(PERSISTENT_GAP_THRESHOLD, 5);
|
|
83696
83758
|
var log = createLogger("IntelligenceService");
|
|
83697
|
-
var runChronologyKey =
|
|
83759
|
+
var runChronologyKey = sql26`coalesce(${runs.finishedAt}, ${runs.createdAt})`;
|
|
83698
83760
|
function analyzableRunPredicates(projectId) {
|
|
83699
83761
|
return [
|
|
83700
83762
|
eq67(runs.projectId, projectId),
|
|
@@ -83762,7 +83824,7 @@ var IntelligenceService = class {
|
|
|
83762
83824
|
// MEASUREMENT: only runs that actually wrote snapshots — see above.
|
|
83763
83825
|
// Index seek on idx_snapshots_run, short-circuited on the first row.
|
|
83764
83826
|
exists(
|
|
83765
|
-
this.db.select({ one:
|
|
83827
|
+
this.db.select({ one: sql26`1` }).from(querySnapshots).where(eq67(querySnapshots.runId, runs.id))
|
|
83766
83828
|
)
|
|
83767
83829
|
)
|
|
83768
83830
|
).orderBy(desc29(runs.finishedAt), desc29(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
|
|
@@ -83848,7 +83910,7 @@ var IntelligenceService = class {
|
|
|
83848
83910
|
const selected = this.db.select().from(gbpLocations).where(and56(
|
|
83849
83911
|
eq67(gbpLocations.projectId, projectId),
|
|
83850
83912
|
eq67(gbpLocations.selected, true),
|
|
83851
|
-
|
|
83913
|
+
gte18(gbpLocations.syncedAt, windowStart),
|
|
83852
83914
|
lte15(gbpLocations.syncedAt, windowEnd)
|
|
83853
83915
|
)).all();
|
|
83854
83916
|
if (selected.length === 0) {
|
|
@@ -84228,7 +84290,7 @@ var IntelligenceService = class {
|
|
|
84228
84290
|
position: gscSearchData.position
|
|
84229
84291
|
}).from(gscSearchData).where(and56(
|
|
84230
84292
|
eq67(gscSearchData.projectId, projectId),
|
|
84231
|
-
|
|
84293
|
+
gte18(gscSearchData.date, window.startDate),
|
|
84232
84294
|
lte15(gscSearchData.date, window.endDate)
|
|
84233
84295
|
)).all();
|
|
84234
84296
|
const byDay = /* @__PURE__ */ new Map();
|