@canonry/canonry 4.117.1 → 4.117.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/assets/agent-workspace/skills/canonry/references/canonry-cli.md +21 -0
- package/assets/assets/{BacklinksPage-Bkafm10m.js → BacklinksPage-CschVQxC.js} +1 -1
- package/assets/assets/{ChartPrimitives-NV_GgqFn.js → ChartPrimitives-D4782Ifx.js} +1 -1
- package/assets/assets/ProjectPage-BSGTpBUJ.js +7 -0
- package/assets/assets/{RunRow-df0d24S6.js → RunRow-ggNGlwdN.js} +1 -1
- package/assets/assets/{RunsPage-CU6-4YTM.js → RunsPage-Bfp0K6Ry.js} +1 -1
- package/assets/assets/{SettingsPage-BKw6B6cd.js → SettingsPage-Cy9SlBJX.js} +1 -1
- package/assets/assets/{TrafficPage-CzpiYHKj.js → TrafficPage-1S2PzSHB.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-CC5nuqM1.js → TrafficSourceDetailPage-CqXCoaod.js} +1 -1
- package/assets/assets/{arrow-left-CbQcW2pL.js → arrow-left-kCK5M8Bp.js} +1 -1
- package/assets/assets/{extract-error-message-CvqIZ-le.js → extract-error-message-C82LAW6q.js} +1 -1
- package/assets/assets/index-DrDNyUhv.css +1 -0
- package/assets/assets/{index-LjcWHaNZ.js → index-i-t64RXw.js} +74 -74
- package/assets/assets/{trash-2-3J2u0woR.js → trash-2-8Pe4v1T0.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-BMBHUFMI.js → chunk-4PMMEFME.js} +42 -1
- package/dist/{chunk-V4SW7SVX.js → chunk-BMPIV35C.js} +696 -417
- package/dist/{chunk-IAJ5TQ4S.js → chunk-EZME2J2G.js} +1196 -1140
- package/dist/{chunk-NY7SC4ES.js → chunk-F2SRZJMY.js} +4 -4
- package/dist/cli.js +121 -77
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-C5YLASIP.js → intelligence-service-GNOE4J35.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +13 -13
- package/assets/assets/ProjectPage-0-NnRxys.js +0 -7
- package/assets/assets/index-B4R1-8hR.css +0 -1
|
@@ -3037,11 +3037,64 @@ function calendarMonthBounds(month) {
|
|
|
3037
3037
|
};
|
|
3038
3038
|
}
|
|
3039
3039
|
|
|
3040
|
+
// ../contracts/src/results-export.ts
|
|
3041
|
+
import { z as z21 } from "zod";
|
|
3042
|
+
var resultsExportFormatSchema = z21.enum(["json", "csv"]);
|
|
3043
|
+
var resultsExportRecordSchema = z21.object({
|
|
3044
|
+
runId: z21.string(),
|
|
3045
|
+
runKind: z21.literal("answer-visibility"),
|
|
3046
|
+
runStatus: runStatusSchema,
|
|
3047
|
+
runTrigger: runTriggerSchema,
|
|
3048
|
+
runCreatedAt: z21.string(),
|
|
3049
|
+
runStartedAt: z21.string().nullable(),
|
|
3050
|
+
runFinishedAt: z21.string().nullable(),
|
|
3051
|
+
snapshotId: z21.string(),
|
|
3052
|
+
snapshotCreatedAt: z21.string(),
|
|
3053
|
+
/** Nullable when a tracked query was removed after this observation. */
|
|
3054
|
+
queryId: z21.string().nullable(),
|
|
3055
|
+
/** Snapshot-time query text, preserving removed queries where available. */
|
|
3056
|
+
query: z21.string().nullable(),
|
|
3057
|
+
provider: z21.string(),
|
|
3058
|
+
model: z21.string().nullable(),
|
|
3059
|
+
location: z21.string().nullable(),
|
|
3060
|
+
citationState: citationStateSchema,
|
|
3061
|
+
cited: z21.boolean(),
|
|
3062
|
+
answerMentioned: z21.boolean().nullable(),
|
|
3063
|
+
// A union keeps OpenAPI generators from dropping `null` on this enum.
|
|
3064
|
+
mentionState: z21.union([mentionStateSchema, z21.null()]),
|
|
3065
|
+
citedDomains: z21.array(z21.string()),
|
|
3066
|
+
competitorOverlap: z21.array(z21.string()),
|
|
3067
|
+
recommendedCompetitors: z21.array(z21.string()),
|
|
3068
|
+
answerText: z21.string().nullable(),
|
|
3069
|
+
groundingSources: z21.array(groundingSourceSchema),
|
|
3070
|
+
searchQueries: z21.array(z21.string())
|
|
3071
|
+
});
|
|
3072
|
+
var resultsExportFiltersSchema = z21.object({
|
|
3073
|
+
since: z21.string().nullable(),
|
|
3074
|
+
until: z21.string().nullable(),
|
|
3075
|
+
includeProbes: z21.boolean()
|
|
3076
|
+
});
|
|
3077
|
+
var resultsExportDtoSchema = z21.object({
|
|
3078
|
+
schemaVersion: z21.literal("canonry.results-export/v1"),
|
|
3079
|
+
generatedAt: z21.string(),
|
|
3080
|
+
project: z21.object({
|
|
3081
|
+
id: z21.string(),
|
|
3082
|
+
name: z21.string(),
|
|
3083
|
+
displayName: z21.string(),
|
|
3084
|
+
canonicalDomain: z21.string(),
|
|
3085
|
+
country: z21.string(),
|
|
3086
|
+
language: z21.string()
|
|
3087
|
+
}),
|
|
3088
|
+
filters: resultsExportFiltersSchema,
|
|
3089
|
+
recordCount: z21.number().int().nonnegative(),
|
|
3090
|
+
records: z21.array(resultsExportRecordSchema)
|
|
3091
|
+
});
|
|
3092
|
+
|
|
3040
3093
|
// ../contracts/src/ga.ts
|
|
3041
|
-
import { z as
|
|
3094
|
+
import { z as z23 } from "zod";
|
|
3042
3095
|
|
|
3043
3096
|
// ../contracts/src/traffic-class.ts
|
|
3044
|
-
import { z as
|
|
3097
|
+
import { z as z22 } from "zod";
|
|
3045
3098
|
|
|
3046
3099
|
// ../contracts/src/formatting.ts
|
|
3047
3100
|
function formatRatio(value) {
|
|
@@ -3128,7 +3181,7 @@ function formatWindowCountDelta(d, countLabel, windowLabel) {
|
|
|
3128
3181
|
}
|
|
3129
3182
|
|
|
3130
3183
|
// ../contracts/src/traffic-class.ts
|
|
3131
|
-
var aiReferralTrafficClassSchema =
|
|
3184
|
+
var aiReferralTrafficClassSchema = z22.enum(["organic", "paid"]);
|
|
3132
3185
|
var AiReferralTrafficClasses = aiReferralTrafficClassSchema.enum;
|
|
3133
3186
|
var PAID_CHANNEL_GROUPS = /* @__PURE__ */ new Set([
|
|
3134
3187
|
"paid search",
|
|
@@ -3198,29 +3251,29 @@ function formatAiReferralClassSummary(counts) {
|
|
|
3198
3251
|
}
|
|
3199
3252
|
|
|
3200
3253
|
// ../contracts/src/ga.ts
|
|
3201
|
-
var ga4ConnectionDtoSchema =
|
|
3202
|
-
id:
|
|
3203
|
-
projectId:
|
|
3204
|
-
propertyId:
|
|
3205
|
-
clientEmail:
|
|
3206
|
-
connected:
|
|
3207
|
-
createdAt:
|
|
3208
|
-
updatedAt:
|
|
3209
|
-
});
|
|
3210
|
-
var ga4TrafficSnapshotDtoSchema =
|
|
3211
|
-
date:
|
|
3212
|
-
landingPage:
|
|
3213
|
-
sessions:
|
|
3214
|
-
organicSessions:
|
|
3215
|
-
users:
|
|
3216
|
-
});
|
|
3217
|
-
var ga4SourceDimensionSchema =
|
|
3218
|
-
var ga4AiReferralDtoSchema =
|
|
3219
|
-
source:
|
|
3220
|
-
medium:
|
|
3254
|
+
var ga4ConnectionDtoSchema = z23.object({
|
|
3255
|
+
id: z23.string(),
|
|
3256
|
+
projectId: z23.string(),
|
|
3257
|
+
propertyId: z23.string(),
|
|
3258
|
+
clientEmail: z23.string(),
|
|
3259
|
+
connected: z23.boolean(),
|
|
3260
|
+
createdAt: z23.string(),
|
|
3261
|
+
updatedAt: z23.string()
|
|
3262
|
+
});
|
|
3263
|
+
var ga4TrafficSnapshotDtoSchema = z23.object({
|
|
3264
|
+
date: z23.string(),
|
|
3265
|
+
landingPage: z23.string(),
|
|
3266
|
+
sessions: z23.number(),
|
|
3267
|
+
organicSessions: z23.number(),
|
|
3268
|
+
users: z23.number()
|
|
3269
|
+
});
|
|
3270
|
+
var ga4SourceDimensionSchema = z23.enum(["session", "first_user", "manual_utm"]);
|
|
3271
|
+
var ga4AiReferralDtoSchema = z23.object({
|
|
3272
|
+
source: z23.string(),
|
|
3273
|
+
medium: z23.string(),
|
|
3221
3274
|
trafficClass: aiReferralTrafficClassSchema,
|
|
3222
|
-
sessions:
|
|
3223
|
-
users:
|
|
3275
|
+
sessions: z23.number(),
|
|
3276
|
+
users: z23.number(),
|
|
3224
3277
|
/**
|
|
3225
3278
|
* The winning attribution dimension for this (source, medium) tuple — the
|
|
3226
3279
|
* one with the highest session count. GA4 emits one row per dimension
|
|
@@ -3230,178 +3283,178 @@ var ga4AiReferralDtoSchema = z22.object({
|
|
|
3230
3283
|
*/
|
|
3231
3284
|
sourceDimension: ga4SourceDimensionSchema
|
|
3232
3285
|
});
|
|
3233
|
-
var ga4AiReferralLandingPageDtoSchema =
|
|
3234
|
-
source:
|
|
3235
|
-
medium:
|
|
3286
|
+
var ga4AiReferralLandingPageDtoSchema = z23.object({
|
|
3287
|
+
source: z23.string(),
|
|
3288
|
+
medium: z23.string(),
|
|
3236
3289
|
trafficClass: aiReferralTrafficClassSchema,
|
|
3237
3290
|
/**
|
|
3238
3291
|
* The winning attribution dimension for this (source, medium, landingPage)
|
|
3239
3292
|
* tuple — the one with the highest session count.
|
|
3240
3293
|
*/
|
|
3241
3294
|
sourceDimension: ga4SourceDimensionSchema,
|
|
3242
|
-
landingPage:
|
|
3243
|
-
sessions:
|
|
3244
|
-
users:
|
|
3245
|
-
});
|
|
3246
|
-
var ga4SocialReferralDtoSchema =
|
|
3247
|
-
source:
|
|
3248
|
-
medium:
|
|
3249
|
-
sessions:
|
|
3250
|
-
users:
|
|
3295
|
+
landingPage: z23.string(),
|
|
3296
|
+
sessions: z23.number(),
|
|
3297
|
+
users: z23.number()
|
|
3298
|
+
});
|
|
3299
|
+
var ga4SocialReferralDtoSchema = z23.object({
|
|
3300
|
+
source: z23.string(),
|
|
3301
|
+
medium: z23.string(),
|
|
3302
|
+
sessions: z23.number(),
|
|
3303
|
+
users: z23.number(),
|
|
3251
3304
|
/** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
|
|
3252
|
-
channelGroup:
|
|
3305
|
+
channelGroup: z23.string()
|
|
3253
3306
|
});
|
|
3254
|
-
var ga4ChannelBucketDtoSchema =
|
|
3255
|
-
sessions:
|
|
3256
|
-
sharePct:
|
|
3257
|
-
sharePctDisplay:
|
|
3307
|
+
var ga4ChannelBucketDtoSchema = z23.object({
|
|
3308
|
+
sessions: z23.number(),
|
|
3309
|
+
sharePct: z23.number(),
|
|
3310
|
+
sharePctDisplay: z23.string()
|
|
3258
3311
|
});
|
|
3259
|
-
var ga4ChannelBreakdownDtoSchema =
|
|
3312
|
+
var ga4ChannelBreakdownDtoSchema = z23.object({
|
|
3260
3313
|
organic: ga4ChannelBucketDtoSchema,
|
|
3261
3314
|
social: ga4ChannelBucketDtoSchema,
|
|
3262
3315
|
direct: ga4ChannelBucketDtoSchema,
|
|
3263
3316
|
ai: ga4ChannelBucketDtoSchema,
|
|
3264
3317
|
other: ga4ChannelBucketDtoSchema
|
|
3265
3318
|
});
|
|
3266
|
-
var ga4TrafficSummaryDtoSchema =
|
|
3267
|
-
totalSessions:
|
|
3268
|
-
totalOrganicSessions:
|
|
3319
|
+
var ga4TrafficSummaryDtoSchema = z23.object({
|
|
3320
|
+
totalSessions: z23.number(),
|
|
3321
|
+
totalOrganicSessions: z23.number(),
|
|
3269
3322
|
/** Direct-channel sessions (sessions with no source — bookmarks, typed URLs, AI-driven traffic with stripped referrer). 0 for legacy rows from before the column was added. */
|
|
3270
|
-
totalDirectSessions:
|
|
3271
|
-
totalUsers:
|
|
3272
|
-
topPages:
|
|
3273
|
-
landingPage:
|
|
3274
|
-
sessions:
|
|
3275
|
-
organicSessions:
|
|
3323
|
+
totalDirectSessions: z23.number(),
|
|
3324
|
+
totalUsers: z23.number(),
|
|
3325
|
+
topPages: z23.array(z23.object({
|
|
3326
|
+
landingPage: z23.string(),
|
|
3327
|
+
sessions: z23.number(),
|
|
3328
|
+
organicSessions: z23.number(),
|
|
3276
3329
|
/** Per-page Direct-channel sessions. 0 for legacy rows. */
|
|
3277
|
-
directSessions:
|
|
3278
|
-
users:
|
|
3330
|
+
directSessions: z23.number(),
|
|
3331
|
+
users: z23.number()
|
|
3279
3332
|
})),
|
|
3280
|
-
aiReferrals:
|
|
3281
|
-
aiReferralLandingPages:
|
|
3333
|
+
aiReferrals: z23.array(ga4AiReferralDtoSchema),
|
|
3334
|
+
aiReferralLandingPages: z23.array(ga4AiReferralLandingPageDtoSchema),
|
|
3282
3335
|
/** Deduped AI session total: MAX(sessions) per date+source+medium across attribution dimensions, then summed. Cross-cutting: can overlap with Direct/Organic/Social via firstUserSource. */
|
|
3283
|
-
aiSessionsDeduped:
|
|
3336
|
+
aiSessionsDeduped: z23.number(),
|
|
3284
3337
|
/** Deduped AI user total: MAX(users) per date+source+medium across attribution dimensions, then summed. */
|
|
3285
|
-
aiUsersDeduped:
|
|
3338
|
+
aiUsersDeduped: z23.number(),
|
|
3286
3339
|
/** Deduped AI sessions whose attribution carries paid intent. */
|
|
3287
|
-
paidAiSessionsDeduped:
|
|
3340
|
+
paidAiSessionsDeduped: z23.number(),
|
|
3288
3341
|
/** Deduped users for paid AI sessions. */
|
|
3289
|
-
paidAiUsersDeduped:
|
|
3342
|
+
paidAiUsersDeduped: z23.number(),
|
|
3290
3343
|
/** Deduped AI sessions without paid intent evidence. */
|
|
3291
|
-
organicAiSessionsDeduped:
|
|
3344
|
+
organicAiSessionsDeduped: z23.number(),
|
|
3292
3345
|
/** Deduped users for organic/non-paid AI sessions. */
|
|
3293
|
-
organicAiUsersDeduped:
|
|
3346
|
+
organicAiUsersDeduped: z23.number(),
|
|
3294
3347
|
/** AI sessions whose CURRENT sessionSource matched an AI engine. Can overlap with raw Organic/Social/Direct totals; `channelBreakdown` removes those overlaps for display. */
|
|
3295
|
-
aiSessionsBySession:
|
|
3348
|
+
aiSessionsBySession: z23.number(),
|
|
3296
3349
|
/** AI users whose CURRENT sessionSource matched an AI engine. Can overlap with raw Organic/Social/Direct totals. */
|
|
3297
|
-
aiUsersBySession:
|
|
3350
|
+
aiUsersBySession: z23.number(),
|
|
3298
3351
|
/** Session-source-only paid AI sessions. */
|
|
3299
|
-
paidAiSessionsBySession:
|
|
3352
|
+
paidAiSessionsBySession: z23.number(),
|
|
3300
3353
|
/** Session-source-only paid AI users. */
|
|
3301
|
-
paidAiUsersBySession:
|
|
3354
|
+
paidAiUsersBySession: z23.number(),
|
|
3302
3355
|
/** Session-source-only organic/non-paid AI sessions. */
|
|
3303
|
-
organicAiSessionsBySession:
|
|
3356
|
+
organicAiSessionsBySession: z23.number(),
|
|
3304
3357
|
/** Session-source-only organic/non-paid AI users. */
|
|
3305
|
-
organicAiUsersBySession:
|
|
3306
|
-
socialReferrals:
|
|
3358
|
+
organicAiUsersBySession: z23.number(),
|
|
3359
|
+
socialReferrals: z23.array(ga4SocialReferralDtoSchema),
|
|
3307
3360
|
/** Total social sessions (session-scoped, no cross-dimension dedup needed). */
|
|
3308
|
-
socialSessions:
|
|
3361
|
+
socialSessions: z23.number(),
|
|
3309
3362
|
/** Total social users (session-scoped, no cross-dimension dedup needed). */
|
|
3310
|
-
socialUsers:
|
|
3363
|
+
socialUsers: z23.number(),
|
|
3311
3364
|
/** Five disjoint buckets used for the channel breakdown. Known AI session-source matches are removed from their native GA4 bucket before shares are computed. */
|
|
3312
3365
|
channelBreakdown: ga4ChannelBreakdownDtoSchema,
|
|
3313
3366
|
/** Organic sessions as a percentage of total sessions (0–100, rounded). */
|
|
3314
|
-
organicSharePct:
|
|
3367
|
+
organicSharePct: z23.number(),
|
|
3315
3368
|
/** Deduped AI sessions as a percentage of total sessions (0–100, rounded). Cross-cutting: can overlap with Direct/Organic/Social. */
|
|
3316
|
-
aiSharePct:
|
|
3369
|
+
aiSharePct: z23.number(),
|
|
3317
3370
|
/** Session-source-only AI sessions as a percentage of total sessions (0–100, rounded). Can overlap with raw Organic/Social/Direct totals. */
|
|
3318
|
-
aiSharePctBySession:
|
|
3371
|
+
aiSharePctBySession: z23.number(),
|
|
3319
3372
|
/** Paid AI sessions as a percentage of total sessions (0–100, rounded). */
|
|
3320
|
-
paidAiSharePct:
|
|
3373
|
+
paidAiSharePct: z23.number(),
|
|
3321
3374
|
/** Session-source paid AI sessions as a percentage of total sessions (0–100, rounded). */
|
|
3322
|
-
paidAiSharePctBySession:
|
|
3375
|
+
paidAiSharePctBySession: z23.number(),
|
|
3323
3376
|
/** Organic/non-paid AI sessions as a percentage of total sessions (0–100, rounded). */
|
|
3324
|
-
organicAiSharePct:
|
|
3377
|
+
organicAiSharePct: z23.number(),
|
|
3325
3378
|
/** Session-source organic/non-paid AI sessions as a percentage of total sessions (0–100, rounded). */
|
|
3326
|
-
organicAiSharePctBySession:
|
|
3379
|
+
organicAiSharePctBySession: z23.number(),
|
|
3327
3380
|
/** Direct-channel sessions as a percentage of total sessions (0–100, rounded). */
|
|
3328
|
-
directSharePct:
|
|
3381
|
+
directSharePct: z23.number(),
|
|
3329
3382
|
/** Social sessions as a percentage of total sessions (0–100, rounded). */
|
|
3330
|
-
socialSharePct:
|
|
3383
|
+
socialSharePct: z23.number(),
|
|
3331
3384
|
/** Display string for organicSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
3332
|
-
organicSharePctDisplay:
|
|
3385
|
+
organicSharePctDisplay: z23.string(),
|
|
3333
3386
|
/** Display string for aiSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
3334
|
-
aiSharePctDisplay:
|
|
3387
|
+
aiSharePctDisplay: z23.string(),
|
|
3335
3388
|
/** Display string for aiSharePctBySession: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
3336
|
-
aiSharePctBySessionDisplay:
|
|
3389
|
+
aiSharePctBySessionDisplay: z23.string(),
|
|
3337
3390
|
/** Display string for paidAiSharePct. */
|
|
3338
|
-
paidAiSharePctDisplay:
|
|
3391
|
+
paidAiSharePctDisplay: z23.string(),
|
|
3339
3392
|
/** Display string for paidAiSharePctBySession. */
|
|
3340
|
-
paidAiSharePctBySessionDisplay:
|
|
3393
|
+
paidAiSharePctBySessionDisplay: z23.string(),
|
|
3341
3394
|
/** Display string for organicAiSharePct. */
|
|
3342
|
-
organicAiSharePctDisplay:
|
|
3395
|
+
organicAiSharePctDisplay: z23.string(),
|
|
3343
3396
|
/** Display string for organicAiSharePctBySession. */
|
|
3344
|
-
organicAiSharePctBySessionDisplay:
|
|
3397
|
+
organicAiSharePctBySessionDisplay: z23.string(),
|
|
3345
3398
|
/** Display string for directSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
3346
|
-
directSharePctDisplay:
|
|
3399
|
+
directSharePctDisplay: z23.string(),
|
|
3347
3400
|
/** Display string for socialSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
3348
|
-
socialSharePctDisplay:
|
|
3401
|
+
socialSharePctDisplay: z23.string(),
|
|
3349
3402
|
/** Sessions not covered by Organic, Social, Direct, or AI (session) channels — e.g. Referral, Email, Paid Search, Display. Always non-negative; clamped to 0 when the four disjoint channels sum above total (rounding edge). */
|
|
3350
|
-
otherSessions:
|
|
3403
|
+
otherSessions: z23.number(),
|
|
3351
3404
|
/** Other sessions as a percentage of total sessions (0–100, rounded). */
|
|
3352
|
-
otherSharePct:
|
|
3405
|
+
otherSharePct: z23.number(),
|
|
3353
3406
|
/** Display string for otherSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
3354
|
-
otherSharePctDisplay:
|
|
3355
|
-
lastSyncedAt:
|
|
3356
|
-
});
|
|
3357
|
-
var ga4StatusDtoSchema =
|
|
3358
|
-
connected:
|
|
3359
|
-
propertyId:
|
|
3360
|
-
clientEmail:
|
|
3361
|
-
authMethod:
|
|
3362
|
-
lastSyncedAt:
|
|
3363
|
-
createdAt:
|
|
3364
|
-
updatedAt:
|
|
3365
|
-
});
|
|
3366
|
-
var ga4SyncResponseDtoSchema =
|
|
3367
|
-
synced:
|
|
3368
|
-
rowCount:
|
|
3369
|
-
aiReferralCount:
|
|
3370
|
-
socialReferralCount:
|
|
3371
|
-
days:
|
|
3372
|
-
syncedAt:
|
|
3407
|
+
otherSharePctDisplay: z23.string(),
|
|
3408
|
+
lastSyncedAt: z23.string().nullable()
|
|
3409
|
+
});
|
|
3410
|
+
var ga4StatusDtoSchema = z23.object({
|
|
3411
|
+
connected: z23.boolean(),
|
|
3412
|
+
propertyId: z23.string().nullable(),
|
|
3413
|
+
clientEmail: z23.string().nullable(),
|
|
3414
|
+
authMethod: z23.enum(["service-account", "oauth"]).nullable(),
|
|
3415
|
+
lastSyncedAt: z23.string().nullable(),
|
|
3416
|
+
createdAt: z23.string().nullable().optional(),
|
|
3417
|
+
updatedAt: z23.string().nullable().optional()
|
|
3418
|
+
});
|
|
3419
|
+
var ga4SyncResponseDtoSchema = z23.object({
|
|
3420
|
+
synced: z23.boolean(),
|
|
3421
|
+
rowCount: z23.number().int().nonnegative(),
|
|
3422
|
+
aiReferralCount: z23.number().int().nonnegative(),
|
|
3423
|
+
socialReferralCount: z23.number().int().nonnegative(),
|
|
3424
|
+
days: z23.number().int().nonnegative(),
|
|
3425
|
+
syncedAt: z23.string(),
|
|
3373
3426
|
/**
|
|
3374
3427
|
* Components that were written this run. Present when `only` is set.
|
|
3375
3428
|
* Always includes `traffic` and `summary` (the share denominator) plus
|
|
3376
3429
|
* the requested channel breakdown — `ai` and/or `social`.
|
|
3377
3430
|
*/
|
|
3378
|
-
syncedComponents:
|
|
3431
|
+
syncedComponents: z23.array(z23.string()).optional()
|
|
3379
3432
|
});
|
|
3380
|
-
var ga4AiReferralHistoryEntrySchema =
|
|
3381
|
-
date:
|
|
3382
|
-
source:
|
|
3383
|
-
medium:
|
|
3433
|
+
var ga4AiReferralHistoryEntrySchema = z23.object({
|
|
3434
|
+
date: z23.string(),
|
|
3435
|
+
source: z23.string(),
|
|
3436
|
+
medium: z23.string(),
|
|
3384
3437
|
trafficClass: aiReferralTrafficClassSchema,
|
|
3385
|
-
landingPage:
|
|
3386
|
-
sessions:
|
|
3387
|
-
users:
|
|
3438
|
+
landingPage: z23.string(),
|
|
3439
|
+
sessions: z23.number(),
|
|
3440
|
+
users: z23.number(),
|
|
3388
3441
|
/** Which GA4 dimension this row came from: session (sessionSource), first_user (firstUserSource), or manual_utm (utm_source parameter) */
|
|
3389
3442
|
sourceDimension: ga4SourceDimensionSchema
|
|
3390
3443
|
});
|
|
3391
|
-
var ga4SocialReferralHistoryEntrySchema =
|
|
3392
|
-
date:
|
|
3393
|
-
source:
|
|
3394
|
-
medium:
|
|
3395
|
-
sessions:
|
|
3396
|
-
users:
|
|
3444
|
+
var ga4SocialReferralHistoryEntrySchema = z23.object({
|
|
3445
|
+
date: z23.string(),
|
|
3446
|
+
source: z23.string(),
|
|
3447
|
+
medium: z23.string(),
|
|
3448
|
+
sessions: z23.number(),
|
|
3449
|
+
users: z23.number(),
|
|
3397
3450
|
/** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
|
|
3398
|
-
channelGroup:
|
|
3451
|
+
channelGroup: z23.string()
|
|
3399
3452
|
});
|
|
3400
|
-
var ga4SessionHistoryEntrySchema =
|
|
3401
|
-
date:
|
|
3402
|
-
sessions:
|
|
3403
|
-
organicSessions:
|
|
3404
|
-
users:
|
|
3453
|
+
var ga4SessionHistoryEntrySchema = z23.object({
|
|
3454
|
+
date: z23.string(),
|
|
3455
|
+
sessions: z23.number(),
|
|
3456
|
+
organicSessions: z23.number(),
|
|
3457
|
+
users: z23.number()
|
|
3405
3458
|
});
|
|
3406
3459
|
|
|
3407
3460
|
// ../contracts/src/answer-visibility.ts
|
|
@@ -3569,50 +3622,50 @@ function escapeRegExp(value) {
|
|
|
3569
3622
|
}
|
|
3570
3623
|
|
|
3571
3624
|
// ../contracts/src/agent.ts
|
|
3572
|
-
import { z as
|
|
3573
|
-
var agentProviderIdSchema =
|
|
3574
|
-
var agentProviderOptionDtoSchema =
|
|
3625
|
+
import { z as z24 } from "zod";
|
|
3626
|
+
var agentProviderIdSchema = z24.enum(["claude", "openai", "gemini", "zai", "deepinfra"]);
|
|
3627
|
+
var agentProviderOptionDtoSchema = z24.object({
|
|
3575
3628
|
/** Stable identifier — what clients pass back as `provider` on the prompt endpoint. */
|
|
3576
3629
|
id: agentProviderIdSchema,
|
|
3577
3630
|
/** Human-readable label for UI pickers, e.g. "Anthropic (Claude)". */
|
|
3578
|
-
label:
|
|
3631
|
+
label: z24.string(),
|
|
3579
3632
|
/** Default model if the caller doesn't pick one. */
|
|
3580
|
-
defaultModel:
|
|
3633
|
+
defaultModel: z24.string(),
|
|
3581
3634
|
/** Whether a usable API key was found (config.yaml or provider env var). */
|
|
3582
|
-
configured:
|
|
3635
|
+
configured: z24.boolean(),
|
|
3583
3636
|
/**
|
|
3584
3637
|
* Where the key resolved from, if any. `null` when `configured === false`.
|
|
3585
3638
|
* Surfaced so the UI can nudge users toward their preferred source of truth.
|
|
3586
3639
|
*/
|
|
3587
|
-
keySource:
|
|
3640
|
+
keySource: z24.enum(["config", "env"]).nullable()
|
|
3588
3641
|
});
|
|
3589
|
-
var agentProvidersResponseDtoSchema =
|
|
3642
|
+
var agentProvidersResponseDtoSchema = z24.object({
|
|
3590
3643
|
/**
|
|
3591
3644
|
* Every provider Aero knows about. `configured === false` entries are
|
|
3592
3645
|
* included so the UI can render them disabled with an onboarding hint.
|
|
3593
3646
|
*/
|
|
3594
|
-
providers:
|
|
3647
|
+
providers: z24.array(agentProviderOptionDtoSchema).default([]),
|
|
3595
3648
|
/**
|
|
3596
3649
|
* Provider Aero auto-picks when no explicit override is passed. Null if
|
|
3597
3650
|
* nothing is configured (install never exchanged a key).
|
|
3598
3651
|
*/
|
|
3599
3652
|
defaultProvider: agentProviderIdSchema.nullable()
|
|
3600
3653
|
});
|
|
3601
|
-
var memorySourceSchema =
|
|
3654
|
+
var memorySourceSchema = z24.enum(["aero", "user", "compaction"]);
|
|
3602
3655
|
var MemorySources = memorySourceSchema.enum;
|
|
3603
3656
|
var AGENT_MEMORY_VALUE_MAX_BYTES = 2 * 1024;
|
|
3604
3657
|
var AGENT_MEMORY_KEY_MAX_LENGTH = 128;
|
|
3605
|
-
var agentMemoryUpsertRequestSchema =
|
|
3606
|
-
key:
|
|
3607
|
-
value:
|
|
3658
|
+
var agentMemoryUpsertRequestSchema = z24.object({
|
|
3659
|
+
key: z24.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH),
|
|
3660
|
+
value: z24.string().min(1)
|
|
3608
3661
|
});
|
|
3609
|
-
var agentMemoryDeleteRequestSchema =
|
|
3610
|
-
key:
|
|
3662
|
+
var agentMemoryDeleteRequestSchema = z24.object({
|
|
3663
|
+
key: z24.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH)
|
|
3611
3664
|
});
|
|
3612
3665
|
|
|
3613
3666
|
// ../contracts/src/backlinks.ts
|
|
3614
|
-
import { z as
|
|
3615
|
-
var backlinkSourceSchema =
|
|
3667
|
+
import { z as z25 } from "zod";
|
|
3668
|
+
var backlinkSourceSchema = z25.enum(["commoncrawl", "bing-webmaster"]);
|
|
3616
3669
|
var BacklinkSources = backlinkSourceSchema.enum;
|
|
3617
3670
|
function computeBacklinkSummaryMetrics(rows) {
|
|
3618
3671
|
if (rows.length === 0) {
|
|
@@ -3628,181 +3681,181 @@ function computeBacklinkSummaryMetrics(rows) {
|
|
|
3628
3681
|
top10HostsShare: share.toFixed(6)
|
|
3629
3682
|
};
|
|
3630
3683
|
}
|
|
3631
|
-
var ccReleaseSyncStatusSchema =
|
|
3684
|
+
var ccReleaseSyncStatusSchema = z25.enum(["queued", "downloading", "querying", "ready", "failed"]);
|
|
3632
3685
|
var CcReleaseSyncStatuses = ccReleaseSyncStatusSchema.enum;
|
|
3633
|
-
var ccReleaseSyncDtoSchema =
|
|
3634
|
-
id:
|
|
3635
|
-
release:
|
|
3686
|
+
var ccReleaseSyncDtoSchema = z25.object({
|
|
3687
|
+
id: z25.string(),
|
|
3688
|
+
release: z25.string(),
|
|
3636
3689
|
status: ccReleaseSyncStatusSchema,
|
|
3637
|
-
phaseDetail:
|
|
3638
|
-
vertexPath:
|
|
3639
|
-
edgesPath:
|
|
3640
|
-
vertexSha256:
|
|
3641
|
-
edgesSha256:
|
|
3642
|
-
vertexBytes:
|
|
3643
|
-
edgesBytes:
|
|
3644
|
-
projectsProcessed:
|
|
3645
|
-
domainsDiscovered:
|
|
3646
|
-
downloadStartedAt:
|
|
3647
|
-
downloadFinishedAt:
|
|
3648
|
-
queryStartedAt:
|
|
3649
|
-
queryFinishedAt:
|
|
3650
|
-
error:
|
|
3651
|
-
createdAt:
|
|
3652
|
-
updatedAt:
|
|
3653
|
-
});
|
|
3654
|
-
var backlinkDomainDtoSchema =
|
|
3655
|
-
linkingDomain:
|
|
3690
|
+
phaseDetail: z25.string().nullable().optional(),
|
|
3691
|
+
vertexPath: z25.string().nullable().optional(),
|
|
3692
|
+
edgesPath: z25.string().nullable().optional(),
|
|
3693
|
+
vertexSha256: z25.string().nullable().optional(),
|
|
3694
|
+
edgesSha256: z25.string().nullable().optional(),
|
|
3695
|
+
vertexBytes: z25.number().int().nullable().optional(),
|
|
3696
|
+
edgesBytes: z25.number().int().nullable().optional(),
|
|
3697
|
+
projectsProcessed: z25.number().int().nullable().optional(),
|
|
3698
|
+
domainsDiscovered: z25.number().int().nullable().optional(),
|
|
3699
|
+
downloadStartedAt: z25.string().nullable().optional(),
|
|
3700
|
+
downloadFinishedAt: z25.string().nullable().optional(),
|
|
3701
|
+
queryStartedAt: z25.string().nullable().optional(),
|
|
3702
|
+
queryFinishedAt: z25.string().nullable().optional(),
|
|
3703
|
+
error: z25.string().nullable().optional(),
|
|
3704
|
+
createdAt: z25.string(),
|
|
3705
|
+
updatedAt: z25.string()
|
|
3706
|
+
});
|
|
3707
|
+
var backlinkDomainDtoSchema = z25.object({
|
|
3708
|
+
linkingDomain: z25.string(),
|
|
3656
3709
|
// For Common Crawl this is the count of distinct hosts within the linking
|
|
3657
3710
|
// domain; for Bing Webmaster it is the count of distinct linking pages (URLs)
|
|
3658
3711
|
// from that linking host. Read alongside `source` — the unit differs per source.
|
|
3659
|
-
numHosts:
|
|
3712
|
+
numHosts: z25.number().int(),
|
|
3660
3713
|
source: backlinkSourceSchema
|
|
3661
3714
|
});
|
|
3662
|
-
var backlinkSummaryDtoSchema =
|
|
3663
|
-
projectId:
|
|
3715
|
+
var backlinkSummaryDtoSchema = z25.object({
|
|
3716
|
+
projectId: z25.string(),
|
|
3664
3717
|
// Window identifier. Common Crawl uses the release slug
|
|
3665
3718
|
// (`cc-main-YYYY-<mon>-<mon>-<mon>`); Bing Webmaster uses a synthetic
|
|
3666
3719
|
// per-sync-day window (`bing-YYYY-MM-DD`).
|
|
3667
|
-
release:
|
|
3668
|
-
targetDomain:
|
|
3669
|
-
totalLinkingDomains:
|
|
3670
|
-
totalHosts:
|
|
3671
|
-
top10HostsShare:
|
|
3672
|
-
queriedAt:
|
|
3720
|
+
release: z25.string(),
|
|
3721
|
+
targetDomain: z25.string(),
|
|
3722
|
+
totalLinkingDomains: z25.number().int(),
|
|
3723
|
+
totalHosts: z25.number().int(),
|
|
3724
|
+
top10HostsShare: z25.string(),
|
|
3725
|
+
queriedAt: z25.string(),
|
|
3673
3726
|
source: backlinkSourceSchema,
|
|
3674
3727
|
// Populated when the response is filtered (e.g. ?excludeCrawlers=1).
|
|
3675
3728
|
// Counts the rows omitted from totalLinkingDomains/totalHosts so callers
|
|
3676
3729
|
// can show "N hidden" hints without re-deriving them.
|
|
3677
|
-
excludedLinkingDomains:
|
|
3678
|
-
excludedHosts:
|
|
3730
|
+
excludedLinkingDomains: z25.number().int().optional(),
|
|
3731
|
+
excludedHosts: z25.number().int().optional()
|
|
3679
3732
|
});
|
|
3680
|
-
var backlinkListResponseSchema =
|
|
3733
|
+
var backlinkListResponseSchema = z25.object({
|
|
3681
3734
|
// The source this response was filtered to (defaults to commoncrawl when the
|
|
3682
3735
|
// caller omits `?source`).
|
|
3683
3736
|
source: backlinkSourceSchema,
|
|
3684
3737
|
summary: backlinkSummaryDtoSchema.nullable(),
|
|
3685
|
-
total:
|
|
3686
|
-
rows:
|
|
3687
|
-
});
|
|
3688
|
-
var backlinkHistoryEntrySchema =
|
|
3689
|
-
release:
|
|
3690
|
-
totalLinkingDomains:
|
|
3691
|
-
totalHosts:
|
|
3692
|
-
top10HostsShare:
|
|
3693
|
-
queriedAt:
|
|
3738
|
+
total: z25.number().int(),
|
|
3739
|
+
rows: z25.array(backlinkDomainDtoSchema)
|
|
3740
|
+
});
|
|
3741
|
+
var backlinkHistoryEntrySchema = z25.object({
|
|
3742
|
+
release: z25.string(),
|
|
3743
|
+
totalLinkingDomains: z25.number().int(),
|
|
3744
|
+
totalHosts: z25.number().int(),
|
|
3745
|
+
top10HostsShare: z25.string(),
|
|
3746
|
+
queriedAt: z25.string(),
|
|
3694
3747
|
source: backlinkSourceSchema
|
|
3695
3748
|
});
|
|
3696
|
-
var backlinkSourceAvailabilityDtoSchema =
|
|
3749
|
+
var backlinkSourceAvailabilityDtoSchema = z25.object({
|
|
3697
3750
|
source: backlinkSourceSchema,
|
|
3698
3751
|
/**
|
|
3699
3752
|
* The source is set up for this project:
|
|
3700
3753
|
* - commoncrawl: `autoExtractBacklinks` enabled AND a `ready` release sync exists.
|
|
3701
3754
|
* - bing-webmaster: a Bing Webmaster connection exists for the project domain.
|
|
3702
3755
|
*/
|
|
3703
|
-
connected:
|
|
3756
|
+
connected: z25.boolean(),
|
|
3704
3757
|
/** Backlink rows exist for this project + source. */
|
|
3705
|
-
hasData:
|
|
3758
|
+
hasData: z25.boolean(),
|
|
3706
3759
|
/** Latest window id with data for this source, null when none. */
|
|
3707
|
-
latestRelease:
|
|
3760
|
+
latestRelease: z25.string().nullable(),
|
|
3708
3761
|
/**
|
|
3709
3762
|
* Linking-domain count in the latest window. Excludes crawler/proxy hosts only
|
|
3710
3763
|
* when the request sets `?excludeCrawlers=1` (default off, matching the summary
|
|
3711
3764
|
* and domains endpoints); the dashboard passes it so the switcher pill matches
|
|
3712
3765
|
* the metric card.
|
|
3713
3766
|
*/
|
|
3714
|
-
totalLinkingDomains:
|
|
3767
|
+
totalLinkingDomains: z25.number().int(),
|
|
3715
3768
|
/** Freshness: `queriedAt` of the latest summary for this source, null when none. */
|
|
3716
|
-
lastSyncedAt:
|
|
3769
|
+
lastSyncedAt: z25.string().nullable()
|
|
3717
3770
|
});
|
|
3718
|
-
var backlinkSourcesResponseSchema =
|
|
3719
|
-
projectId:
|
|
3720
|
-
targetDomain:
|
|
3771
|
+
var backlinkSourcesResponseSchema = z25.object({
|
|
3772
|
+
projectId: z25.string(),
|
|
3773
|
+
targetDomain: z25.string(),
|
|
3721
3774
|
/** Availability for every known source, in a stable order. */
|
|
3722
|
-
sources:
|
|
3723
|
-
anyConnected:
|
|
3724
|
-
anyData:
|
|
3725
|
-
});
|
|
3726
|
-
var backlinksInstallStatusDtoSchema =
|
|
3727
|
-
duckdbInstalled:
|
|
3728
|
-
duckdbVersion:
|
|
3729
|
-
duckdbSpec:
|
|
3730
|
-
pluginDir:
|
|
3731
|
-
});
|
|
3732
|
-
var backlinksInstallResultDtoSchema =
|
|
3733
|
-
installed:
|
|
3734
|
-
version:
|
|
3735
|
-
path:
|
|
3736
|
-
alreadyPresent:
|
|
3737
|
-
});
|
|
3738
|
-
var ccAvailableReleaseSchema =
|
|
3739
|
-
release:
|
|
3740
|
-
vertexUrl:
|
|
3741
|
-
edgesUrl:
|
|
3742
|
-
vertexBytes:
|
|
3743
|
-
edgesBytes:
|
|
3744
|
-
lastModified:
|
|
3745
|
-
});
|
|
3746
|
-
var ccCachedReleaseSchema =
|
|
3747
|
-
release:
|
|
3775
|
+
sources: z25.array(backlinkSourceAvailabilityDtoSchema),
|
|
3776
|
+
anyConnected: z25.boolean(),
|
|
3777
|
+
anyData: z25.boolean()
|
|
3778
|
+
});
|
|
3779
|
+
var backlinksInstallStatusDtoSchema = z25.object({
|
|
3780
|
+
duckdbInstalled: z25.boolean(),
|
|
3781
|
+
duckdbVersion: z25.string().nullable().optional(),
|
|
3782
|
+
duckdbSpec: z25.string(),
|
|
3783
|
+
pluginDir: z25.string()
|
|
3784
|
+
});
|
|
3785
|
+
var backlinksInstallResultDtoSchema = z25.object({
|
|
3786
|
+
installed: z25.boolean(),
|
|
3787
|
+
version: z25.string(),
|
|
3788
|
+
path: z25.string(),
|
|
3789
|
+
alreadyPresent: z25.boolean()
|
|
3790
|
+
});
|
|
3791
|
+
var ccAvailableReleaseSchema = z25.object({
|
|
3792
|
+
release: z25.string(),
|
|
3793
|
+
vertexUrl: z25.string(),
|
|
3794
|
+
edgesUrl: z25.string(),
|
|
3795
|
+
vertexBytes: z25.number().int().nullable(),
|
|
3796
|
+
edgesBytes: z25.number().int().nullable(),
|
|
3797
|
+
lastModified: z25.string().nullable()
|
|
3798
|
+
});
|
|
3799
|
+
var ccCachedReleaseSchema = z25.object({
|
|
3800
|
+
release: z25.string(),
|
|
3748
3801
|
syncStatus: ccReleaseSyncStatusSchema.nullable(),
|
|
3749
|
-
bytes:
|
|
3750
|
-
lastUsedAt:
|
|
3802
|
+
bytes: z25.number().int(),
|
|
3803
|
+
lastUsedAt: z25.string().nullable()
|
|
3751
3804
|
});
|
|
3752
3805
|
|
|
3753
3806
|
// ../contracts/src/composites.ts
|
|
3754
|
-
import { z as
|
|
3755
|
-
var metricToneSchema =
|
|
3756
|
-
var scoreSummarySchema =
|
|
3757
|
-
label:
|
|
3758
|
-
value:
|
|
3759
|
-
delta:
|
|
3807
|
+
import { z as z26 } from "zod";
|
|
3808
|
+
var metricToneSchema = z26.enum(["positive", "caution", "negative", "neutral"]);
|
|
3809
|
+
var scoreSummarySchema = z26.object({
|
|
3810
|
+
label: z26.string(),
|
|
3811
|
+
value: z26.string(),
|
|
3812
|
+
delta: z26.string(),
|
|
3760
3813
|
tone: metricToneSchema,
|
|
3761
|
-
description:
|
|
3762
|
-
tooltip:
|
|
3763
|
-
trend:
|
|
3764
|
-
progress:
|
|
3765
|
-
providerCoverage:
|
|
3814
|
+
description: z26.string(),
|
|
3815
|
+
tooltip: z26.string().optional(),
|
|
3816
|
+
trend: z26.array(z26.number()),
|
|
3817
|
+
progress: z26.number().optional(),
|
|
3818
|
+
providerCoverage: z26.string().optional()
|
|
3766
3819
|
});
|
|
3767
3820
|
var mentionShareSchema = scoreSummarySchema.extend({
|
|
3768
|
-
breakdown:
|
|
3769
|
-
projectMentionSnapshots:
|
|
3770
|
-
competitorMentionSnapshots:
|
|
3771
|
-
perCompetitor:
|
|
3772
|
-
domain:
|
|
3773
|
-
mentionSnapshots:
|
|
3774
|
-
shareOfCompetitiveTotal:
|
|
3821
|
+
breakdown: z26.object({
|
|
3822
|
+
projectMentionSnapshots: z26.number().int().nonnegative(),
|
|
3823
|
+
competitorMentionSnapshots: z26.number().int().nonnegative(),
|
|
3824
|
+
perCompetitor: z26.array(z26.object({
|
|
3825
|
+
domain: z26.string(),
|
|
3826
|
+
mentionSnapshots: z26.number().int().nonnegative(),
|
|
3827
|
+
shareOfCompetitiveTotal: z26.number()
|
|
3775
3828
|
})),
|
|
3776
|
-
snapshotsWithAnswerText:
|
|
3777
|
-
snapshotsTotal:
|
|
3829
|
+
snapshotsWithAnswerText: z26.number().int().nonnegative(),
|
|
3830
|
+
snapshotsTotal: z26.number().int().nonnegative()
|
|
3778
3831
|
})
|
|
3779
3832
|
});
|
|
3780
|
-
var movementSummarySchema =
|
|
3781
|
-
gained:
|
|
3782
|
-
lost:
|
|
3833
|
+
var movementSummarySchema = z26.object({
|
|
3834
|
+
gained: z26.number().int().nonnegative(),
|
|
3835
|
+
lost: z26.number().int().nonnegative(),
|
|
3783
3836
|
tone: metricToneSchema,
|
|
3784
|
-
hasPreviousRun:
|
|
3785
|
-
gainedQueries:
|
|
3786
|
-
lostQueries:
|
|
3787
|
-
});
|
|
3788
|
-
var movementComparisonSchema =
|
|
3789
|
-
hasPreviousRun:
|
|
3790
|
-
comparable:
|
|
3791
|
-
querySetChanged:
|
|
3792
|
-
previousRunAt:
|
|
3793
|
-
currentQueryCount:
|
|
3794
|
-
previousQueryCount:
|
|
3795
|
-
comparableQueryCount:
|
|
3796
|
-
addedQueryCount:
|
|
3797
|
-
removedQueryCount:
|
|
3798
|
-
addedQueries:
|
|
3799
|
-
removedQueries:
|
|
3800
|
-
});
|
|
3801
|
-
var projectOverviewInsightSchema =
|
|
3802
|
-
id:
|
|
3803
|
-
projectId:
|
|
3804
|
-
runId:
|
|
3805
|
-
type:
|
|
3837
|
+
hasPreviousRun: z26.boolean(),
|
|
3838
|
+
gainedQueries: z26.array(z26.string()).optional(),
|
|
3839
|
+
lostQueries: z26.array(z26.string()).optional()
|
|
3840
|
+
});
|
|
3841
|
+
var movementComparisonSchema = z26.object({
|
|
3842
|
+
hasPreviousRun: z26.boolean(),
|
|
3843
|
+
comparable: z26.boolean(),
|
|
3844
|
+
querySetChanged: z26.boolean(),
|
|
3845
|
+
previousRunAt: z26.string().nullable(),
|
|
3846
|
+
currentQueryCount: z26.number().int().nonnegative(),
|
|
3847
|
+
previousQueryCount: z26.number().int().nonnegative(),
|
|
3848
|
+
comparableQueryCount: z26.number().int().nonnegative(),
|
|
3849
|
+
addedQueryCount: z26.number().int().nonnegative(),
|
|
3850
|
+
removedQueryCount: z26.number().int().nonnegative(),
|
|
3851
|
+
addedQueries: z26.array(z26.string()),
|
|
3852
|
+
removedQueries: z26.array(z26.string())
|
|
3853
|
+
});
|
|
3854
|
+
var projectOverviewInsightSchema = z26.object({
|
|
3855
|
+
id: z26.string(),
|
|
3856
|
+
projectId: z26.string(),
|
|
3857
|
+
runId: z26.string().nullable(),
|
|
3858
|
+
type: z26.enum([
|
|
3806
3859
|
"regression",
|
|
3807
3860
|
"gain",
|
|
3808
3861
|
"opportunity",
|
|
@@ -3818,70 +3871,70 @@ var projectOverviewInsightSchema = z25.object({
|
|
|
3818
3871
|
"gbp-metric-drop",
|
|
3819
3872
|
"gbp-keyword-drop"
|
|
3820
3873
|
]),
|
|
3821
|
-
severity:
|
|
3822
|
-
title:
|
|
3823
|
-
query:
|
|
3824
|
-
provider:
|
|
3825
|
-
recommendation:
|
|
3826
|
-
action:
|
|
3827
|
-
target:
|
|
3828
|
-
reason:
|
|
3874
|
+
severity: z26.enum(["critical", "high", "medium", "low"]),
|
|
3875
|
+
title: z26.string(),
|
|
3876
|
+
query: z26.string(),
|
|
3877
|
+
provider: z26.string(),
|
|
3878
|
+
recommendation: z26.object({
|
|
3879
|
+
action: z26.string(),
|
|
3880
|
+
target: z26.string().optional(),
|
|
3881
|
+
reason: z26.string()
|
|
3829
3882
|
}).optional(),
|
|
3830
|
-
cause:
|
|
3831
|
-
cause:
|
|
3832
|
-
competitorDomain:
|
|
3833
|
-
details:
|
|
3883
|
+
cause: z26.object({
|
|
3884
|
+
cause: z26.string(),
|
|
3885
|
+
competitorDomain: z26.string().optional(),
|
|
3886
|
+
details: z26.string().optional()
|
|
3834
3887
|
}).optional(),
|
|
3835
|
-
dismissed:
|
|
3836
|
-
createdAt:
|
|
3837
|
-
});
|
|
3838
|
-
var projectOverviewHealthSchema =
|
|
3839
|
-
id:
|
|
3840
|
-
projectId:
|
|
3841
|
-
runId:
|
|
3842
|
-
overallCitedRate:
|
|
3843
|
-
overallMentionRate:
|
|
3844
|
-
totalPairs:
|
|
3845
|
-
citedPairs:
|
|
3846
|
-
mentionedPairs:
|
|
3847
|
-
providerBreakdown:
|
|
3848
|
-
citedRate:
|
|
3849
|
-
mentionRate:
|
|
3850
|
-
cited:
|
|
3851
|
-
mentioned:
|
|
3852
|
-
total:
|
|
3888
|
+
dismissed: z26.boolean(),
|
|
3889
|
+
createdAt: z26.string()
|
|
3890
|
+
});
|
|
3891
|
+
var projectOverviewHealthSchema = z26.object({
|
|
3892
|
+
id: z26.string(),
|
|
3893
|
+
projectId: z26.string(),
|
|
3894
|
+
runId: z26.string().nullable(),
|
|
3895
|
+
overallCitedRate: z26.number(),
|
|
3896
|
+
overallMentionRate: z26.number(),
|
|
3897
|
+
totalPairs: z26.number().int().nonnegative(),
|
|
3898
|
+
citedPairs: z26.number().int().nonnegative(),
|
|
3899
|
+
mentionedPairs: z26.number().int().nonnegative(),
|
|
3900
|
+
providerBreakdown: z26.record(z26.string(), z26.object({
|
|
3901
|
+
citedRate: z26.number(),
|
|
3902
|
+
mentionRate: z26.number(),
|
|
3903
|
+
cited: z26.number().int().nonnegative(),
|
|
3904
|
+
mentioned: z26.number().int().nonnegative(),
|
|
3905
|
+
total: z26.number().int().nonnegative()
|
|
3853
3906
|
})),
|
|
3854
|
-
createdAt:
|
|
3855
|
-
status:
|
|
3856
|
-
reason:
|
|
3907
|
+
createdAt: z26.string(),
|
|
3908
|
+
status: z26.enum(["ready", "no-data"]),
|
|
3909
|
+
reason: z26.literal("no-runs-yet").optional()
|
|
3857
3910
|
});
|
|
3858
|
-
var projectOverviewDtoSchema =
|
|
3911
|
+
var projectOverviewDtoSchema = z26.object({
|
|
3859
3912
|
project: projectDtoSchema,
|
|
3860
3913
|
latestRun: latestProjectRunDtoSchema,
|
|
3861
3914
|
health: projectOverviewHealthSchema.nullable(),
|
|
3862
|
-
topInsights:
|
|
3863
|
-
queryCounts:
|
|
3864
|
-
totalQueries:
|
|
3865
|
-
citedQueries:
|
|
3866
|
-
notCitedQueries:
|
|
3867
|
-
citedRate:
|
|
3868
|
-
mentionedQueries:
|
|
3869
|
-
notMentionedQueries:
|
|
3870
|
-
mentionRate:
|
|
3915
|
+
topInsights: z26.array(projectOverviewInsightSchema),
|
|
3916
|
+
queryCounts: z26.object({
|
|
3917
|
+
totalQueries: z26.number().int().nonnegative(),
|
|
3918
|
+
citedQueries: z26.number().int().nonnegative(),
|
|
3919
|
+
notCitedQueries: z26.number().int().nonnegative(),
|
|
3920
|
+
citedRate: z26.number(),
|
|
3921
|
+
mentionedQueries: z26.number().int().nonnegative(),
|
|
3922
|
+
notMentionedQueries: z26.number().int().nonnegative(),
|
|
3923
|
+
mentionRate: z26.number()
|
|
3871
3924
|
}),
|
|
3872
|
-
providers:
|
|
3873
|
-
provider:
|
|
3874
|
-
citedRate:
|
|
3875
|
-
cited:
|
|
3876
|
-
total:
|
|
3925
|
+
providers: z26.array(z26.object({
|
|
3926
|
+
provider: z26.string(),
|
|
3927
|
+
citedRate: z26.number(),
|
|
3928
|
+
cited: z26.number().int().nonnegative(),
|
|
3929
|
+
total: z26.number().int().nonnegative()
|
|
3877
3930
|
})),
|
|
3878
|
-
transitions:
|
|
3879
|
-
since:
|
|
3880
|
-
gained:
|
|
3881
|
-
lost:
|
|
3882
|
-
emerging:
|
|
3931
|
+
transitions: z26.object({
|
|
3932
|
+
since: z26.string().nullable(),
|
|
3933
|
+
gained: z26.number().int().nonnegative(),
|
|
3934
|
+
lost: z26.number().int().nonnegative(),
|
|
3935
|
+
emerging: z26.number().int().nonnegative()
|
|
3883
3936
|
}),
|
|
3884
|
-
scores:
|
|
3937
|
+
scores: z26.object({
|
|
3885
3938
|
mention: scoreSummarySchema,
|
|
3886
3939
|
visibility: scoreSummarySchema,
|
|
3887
3940
|
mentionShare: mentionShareSchema,
|
|
@@ -3895,72 +3948,72 @@ var projectOverviewDtoSchema = z25.object({
|
|
|
3895
3948
|
citationMovement: movementSummarySchema,
|
|
3896
3949
|
mentionMovement: movementSummarySchema,
|
|
3897
3950
|
movementComparison: movementComparisonSchema,
|
|
3898
|
-
competitors:
|
|
3899
|
-
id:
|
|
3900
|
-
domain:
|
|
3901
|
-
citationCount:
|
|
3902
|
-
totalQueries:
|
|
3903
|
-
pressureLabel:
|
|
3904
|
-
citedQueries:
|
|
3951
|
+
competitors: z26.array(z26.object({
|
|
3952
|
+
id: z26.string(),
|
|
3953
|
+
domain: z26.string(),
|
|
3954
|
+
citationCount: z26.number().int().nonnegative(),
|
|
3955
|
+
totalQueries: z26.number().int().nonnegative(),
|
|
3956
|
+
pressureLabel: z26.enum(["None", "Low", "Moderate", "High"]),
|
|
3957
|
+
citedQueries: z26.array(z26.string())
|
|
3905
3958
|
})),
|
|
3906
|
-
providerScores:
|
|
3907
|
-
provider:
|
|
3908
|
-
model:
|
|
3909
|
-
score:
|
|
3910
|
-
cited:
|
|
3911
|
-
total:
|
|
3912
|
-
trend:
|
|
3959
|
+
providerScores: z26.array(z26.object({
|
|
3960
|
+
provider: z26.string(),
|
|
3961
|
+
model: z26.string().nullable(),
|
|
3962
|
+
score: z26.number(),
|
|
3963
|
+
cited: z26.number().int().nonnegative(),
|
|
3964
|
+
total: z26.number().int().nonnegative(),
|
|
3965
|
+
trend: z26.array(z26.number()).optional()
|
|
3913
3966
|
})),
|
|
3914
|
-
attentionItems:
|
|
3915
|
-
id:
|
|
3967
|
+
attentionItems: z26.array(z26.object({
|
|
3968
|
+
id: z26.string(),
|
|
3916
3969
|
tone: metricToneSchema,
|
|
3917
|
-
title:
|
|
3918
|
-
detail:
|
|
3919
|
-
actionLabel:
|
|
3920
|
-
href:
|
|
3970
|
+
title: z26.string(),
|
|
3971
|
+
detail: z26.string(),
|
|
3972
|
+
actionLabel: z26.string(),
|
|
3973
|
+
href: z26.string()
|
|
3921
3974
|
})),
|
|
3922
|
-
runHistory:
|
|
3923
|
-
runId:
|
|
3924
|
-
createdAt:
|
|
3925
|
-
citedCount:
|
|
3926
|
-
totalCount:
|
|
3927
|
-
citationRate:
|
|
3928
|
-
mentionedCount:
|
|
3929
|
-
mentionRate:
|
|
3930
|
-
status:
|
|
3975
|
+
runHistory: z26.array(z26.object({
|
|
3976
|
+
runId: z26.string(),
|
|
3977
|
+
createdAt: z26.string(),
|
|
3978
|
+
citedCount: z26.number().int().nonnegative(),
|
|
3979
|
+
totalCount: z26.number().int().nonnegative(),
|
|
3980
|
+
citationRate: z26.number(),
|
|
3981
|
+
mentionedCount: z26.number().int().nonnegative(),
|
|
3982
|
+
mentionRate: z26.number(),
|
|
3983
|
+
status: z26.string()
|
|
3931
3984
|
})),
|
|
3932
|
-
suggestedQueries:
|
|
3933
|
-
rows:
|
|
3934
|
-
query:
|
|
3935
|
-
impressions:
|
|
3936
|
-
clicks:
|
|
3937
|
-
avgPosition:
|
|
3938
|
-
reason:
|
|
3985
|
+
suggestedQueries: z26.object({
|
|
3986
|
+
rows: z26.array(z26.object({
|
|
3987
|
+
query: z26.string(),
|
|
3988
|
+
impressions: z26.number(),
|
|
3989
|
+
clicks: z26.number(),
|
|
3990
|
+
avgPosition: z26.number(),
|
|
3991
|
+
reason: z26.string()
|
|
3939
3992
|
})),
|
|
3940
|
-
totalCandidates:
|
|
3941
|
-
skippedAlreadyTracked:
|
|
3993
|
+
totalCandidates: z26.number().int().nonnegative(),
|
|
3994
|
+
skippedAlreadyTracked: z26.number().int().nonnegative()
|
|
3942
3995
|
}),
|
|
3943
|
-
dateRangeLabel:
|
|
3944
|
-
contextLabel:
|
|
3945
|
-
});
|
|
3946
|
-
var searchHitKindSchema =
|
|
3947
|
-
var projectSearchSnapshotHitSchema =
|
|
3948
|
-
kind:
|
|
3949
|
-
id:
|
|
3950
|
-
runId:
|
|
3951
|
-
query:
|
|
3952
|
-
provider:
|
|
3953
|
-
model:
|
|
3996
|
+
dateRangeLabel: z26.string(),
|
|
3997
|
+
contextLabel: z26.string()
|
|
3998
|
+
});
|
|
3999
|
+
var searchHitKindSchema = z26.enum(["snapshot", "insight"]);
|
|
4000
|
+
var projectSearchSnapshotHitSchema = z26.object({
|
|
4001
|
+
kind: z26.literal("snapshot"),
|
|
4002
|
+
id: z26.string(),
|
|
4003
|
+
runId: z26.string(),
|
|
4004
|
+
query: z26.string(),
|
|
4005
|
+
provider: z26.string(),
|
|
4006
|
+
model: z26.string().nullable(),
|
|
3954
4007
|
citationState: citationStateSchema,
|
|
3955
|
-
matchedField:
|
|
3956
|
-
snippet:
|
|
3957
|
-
createdAt:
|
|
3958
|
-
});
|
|
3959
|
-
var projectSearchInsightHitSchema =
|
|
3960
|
-
kind:
|
|
3961
|
-
id:
|
|
3962
|
-
runId:
|
|
3963
|
-
type:
|
|
4008
|
+
matchedField: z26.enum(["answerText", "citedDomains", "searchQueries", "query"]),
|
|
4009
|
+
snippet: z26.string(),
|
|
4010
|
+
createdAt: z26.string()
|
|
4011
|
+
});
|
|
4012
|
+
var projectSearchInsightHitSchema = z26.object({
|
|
4013
|
+
kind: z26.literal("insight"),
|
|
4014
|
+
id: z26.string(),
|
|
4015
|
+
runId: z26.string().nullable(),
|
|
4016
|
+
type: z26.enum([
|
|
3964
4017
|
"regression",
|
|
3965
4018
|
"gain",
|
|
3966
4019
|
"opportunity",
|
|
@@ -3977,29 +4030,29 @@ var projectSearchInsightHitSchema = z25.object({
|
|
|
3977
4030
|
"gbp-metric-drop",
|
|
3978
4031
|
"gbp-keyword-drop"
|
|
3979
4032
|
]),
|
|
3980
|
-
severity:
|
|
3981
|
-
title:
|
|
3982
|
-
query:
|
|
3983
|
-
provider:
|
|
3984
|
-
matchedField:
|
|
3985
|
-
snippet:
|
|
3986
|
-
dismissed:
|
|
3987
|
-
createdAt:
|
|
3988
|
-
});
|
|
3989
|
-
var projectSearchHitSchema =
|
|
4033
|
+
severity: z26.enum(["critical", "high", "medium", "low"]),
|
|
4034
|
+
title: z26.string(),
|
|
4035
|
+
query: z26.string(),
|
|
4036
|
+
provider: z26.string(),
|
|
4037
|
+
matchedField: z26.enum(["title", "query", "recommendation", "cause"]),
|
|
4038
|
+
snippet: z26.string(),
|
|
4039
|
+
dismissed: z26.boolean(),
|
|
4040
|
+
createdAt: z26.string()
|
|
4041
|
+
});
|
|
4042
|
+
var projectSearchHitSchema = z26.discriminatedUnion("kind", [
|
|
3990
4043
|
projectSearchSnapshotHitSchema,
|
|
3991
4044
|
projectSearchInsightHitSchema
|
|
3992
4045
|
]);
|
|
3993
|
-
var projectSearchResponseSchema =
|
|
3994
|
-
query:
|
|
3995
|
-
totalHits:
|
|
3996
|
-
truncated:
|
|
3997
|
-
hits:
|
|
4046
|
+
var projectSearchResponseSchema = z26.object({
|
|
4047
|
+
query: z26.string(),
|
|
4048
|
+
totalHits: z26.number().int().nonnegative(),
|
|
4049
|
+
truncated: z26.boolean(),
|
|
4050
|
+
hits: z26.array(projectSearchHitSchema)
|
|
3998
4051
|
});
|
|
3999
4052
|
|
|
4000
4053
|
// ../contracts/src/content.ts
|
|
4001
|
-
import { z as
|
|
4002
|
-
var contentActionSchema =
|
|
4054
|
+
import { z as z27 } from "zod";
|
|
4055
|
+
var contentActionSchema = z27.enum(["create", "expand", "refresh", "add-schema"]);
|
|
4003
4056
|
var ContentActions = contentActionSchema.enum;
|
|
4004
4057
|
function contentActionLabel(action) {
|
|
4005
4058
|
switch (action) {
|
|
@@ -4013,9 +4066,9 @@ function contentActionLabel(action) {
|
|
|
4013
4066
|
return "Add schema";
|
|
4014
4067
|
}
|
|
4015
4068
|
}
|
|
4016
|
-
var demandSourceSchema =
|
|
4069
|
+
var demandSourceSchema = z27.enum(["gsc", "competitor-evidence", "both"]);
|
|
4017
4070
|
var DemandSources = demandSourceSchema.enum;
|
|
4018
|
-
var actionConfidenceSchema =
|
|
4071
|
+
var actionConfidenceSchema = z27.enum(["high", "medium", "low"]);
|
|
4019
4072
|
var ActionConfidences = actionConfidenceSchema.enum;
|
|
4020
4073
|
function actionConfidenceLabel(confidence) {
|
|
4021
4074
|
switch (confidence) {
|
|
@@ -4027,7 +4080,7 @@ function actionConfidenceLabel(confidence) {
|
|
|
4027
4080
|
return "Low";
|
|
4028
4081
|
}
|
|
4029
4082
|
}
|
|
4030
|
-
var pageTypeSchema =
|
|
4083
|
+
var pageTypeSchema = z27.enum([
|
|
4031
4084
|
"blog-post",
|
|
4032
4085
|
"comparison",
|
|
4033
4086
|
"listicle",
|
|
@@ -4036,7 +4089,7 @@ var pageTypeSchema = z26.enum([
|
|
|
4036
4089
|
"glossary"
|
|
4037
4090
|
]);
|
|
4038
4091
|
var PageTypes = pageTypeSchema.enum;
|
|
4039
|
-
var contentActionStateSchema =
|
|
4092
|
+
var contentActionStateSchema = z27.enum([
|
|
4040
4093
|
"proposed",
|
|
4041
4094
|
"briefed",
|
|
4042
4095
|
"payload-generated",
|
|
@@ -4046,7 +4099,7 @@ var contentActionStateSchema = z26.enum([
|
|
|
4046
4099
|
"dismissed"
|
|
4047
4100
|
]);
|
|
4048
4101
|
var ContentActionStates = contentActionStateSchema.enum;
|
|
4049
|
-
var winnabilityClassSchema =
|
|
4102
|
+
var winnabilityClassSchema = z27.enum(["ownable", "ceded"]);
|
|
4050
4103
|
var WinnabilityClasses = winnabilityClassSchema.enum;
|
|
4051
4104
|
function winnabilityClassLabel(winnabilityClass) {
|
|
4052
4105
|
switch (winnabilityClass) {
|
|
@@ -4081,40 +4134,40 @@ function deriveWinnabilityClass(citedSurfaceDomains, surfaceClasses, threshold =
|
|
|
4081
4134
|
winnability
|
|
4082
4135
|
};
|
|
4083
4136
|
}
|
|
4084
|
-
var ourBestPageSchema =
|
|
4085
|
-
url:
|
|
4086
|
-
gscImpressions:
|
|
4087
|
-
gscClicks:
|
|
4137
|
+
var ourBestPageSchema = z27.object({
|
|
4138
|
+
url: z27.string(),
|
|
4139
|
+
gscImpressions: z27.number().nonnegative(),
|
|
4140
|
+
gscClicks: z27.number().nonnegative(),
|
|
4088
4141
|
// Null when the page came from the inventory fallback (no GSC ranking data).
|
|
4089
|
-
gscAvgPosition:
|
|
4090
|
-
organicSessions:
|
|
4142
|
+
gscAvgPosition: z27.number().nonnegative().nullable(),
|
|
4143
|
+
organicSessions: z27.number().nonnegative()
|
|
4091
4144
|
});
|
|
4092
|
-
var winningCompetitorSchema =
|
|
4093
|
-
domain:
|
|
4094
|
-
url:
|
|
4095
|
-
title:
|
|
4096
|
-
citationCount:
|
|
4145
|
+
var winningCompetitorSchema = z27.object({
|
|
4146
|
+
domain: z27.string(),
|
|
4147
|
+
url: z27.string(),
|
|
4148
|
+
title: z27.string(),
|
|
4149
|
+
citationCount: z27.number().int().nonnegative()
|
|
4097
4150
|
});
|
|
4098
|
-
var scoreBreakdownSchema =
|
|
4099
|
-
demand:
|
|
4100
|
-
competitor:
|
|
4101
|
-
absence:
|
|
4102
|
-
gapSeverity:
|
|
4151
|
+
var scoreBreakdownSchema = z27.object({
|
|
4152
|
+
demand: z27.number(),
|
|
4153
|
+
competitor: z27.number(),
|
|
4154
|
+
absence: z27.number(),
|
|
4155
|
+
gapSeverity: z27.number()
|
|
4103
4156
|
});
|
|
4104
|
-
var existingActionRefSchema =
|
|
4105
|
-
actionId:
|
|
4157
|
+
var existingActionRefSchema = z27.object({
|
|
4158
|
+
actionId: z27.string(),
|
|
4106
4159
|
state: contentActionStateSchema,
|
|
4107
|
-
lastUpdated:
|
|
4160
|
+
lastUpdated: z27.string()
|
|
4108
4161
|
});
|
|
4109
|
-
var contentTargetRowDtoSchema =
|
|
4110
|
-
targetRef:
|
|
4111
|
-
query:
|
|
4162
|
+
var contentTargetRowDtoSchema = z27.object({
|
|
4163
|
+
targetRef: z27.string(),
|
|
4164
|
+
query: z27.string(),
|
|
4112
4165
|
action: contentActionSchema,
|
|
4113
4166
|
ourBestPage: ourBestPageSchema.nullable(),
|
|
4114
4167
|
winningCompetitor: winningCompetitorSchema.nullable(),
|
|
4115
|
-
score:
|
|
4168
|
+
score: z27.number(),
|
|
4116
4169
|
scoreBreakdown: scoreBreakdownSchema,
|
|
4117
|
-
drivers:
|
|
4170
|
+
drivers: z27.array(z27.string()),
|
|
4118
4171
|
demandSource: demandSourceSchema,
|
|
4119
4172
|
actionConfidence: actionConfidenceSchema,
|
|
4120
4173
|
existingAction: existingActionRefSchema.nullable(),
|
|
@@ -4129,134 +4182,134 @@ var contentTargetRowDtoSchema = z26.object({
|
|
|
4129
4182
|
* `[0, 1]`. `null` when the gate failed open (no classification coverage for
|
|
4130
4183
|
* the cited surface) — distinct from a computed `1.0`.
|
|
4131
4184
|
*/
|
|
4132
|
-
winnability:
|
|
4133
|
-
});
|
|
4134
|
-
var contentTargetsResponseDtoSchema =
|
|
4135
|
-
targets:
|
|
4136
|
-
contextMetrics:
|
|
4137
|
-
totalAiReferralSessions:
|
|
4138
|
-
latestRunId:
|
|
4139
|
-
runTimestamp:
|
|
4185
|
+
winnability: z27.number().min(0).max(1).nullable()
|
|
4186
|
+
});
|
|
4187
|
+
var contentTargetsResponseDtoSchema = z27.object({
|
|
4188
|
+
targets: z27.array(contentTargetRowDtoSchema),
|
|
4189
|
+
contextMetrics: z27.object({
|
|
4190
|
+
totalAiReferralSessions: z27.number().int().nonnegative(),
|
|
4191
|
+
latestRunId: z27.string(),
|
|
4192
|
+
runTimestamp: z27.string()
|
|
4140
4193
|
})
|
|
4141
4194
|
});
|
|
4142
|
-
var contentTargetDismissalDtoSchema =
|
|
4143
|
-
targetRef:
|
|
4144
|
-
addressedUrl:
|
|
4145
|
-
note:
|
|
4146
|
-
dismissedAt:
|
|
4195
|
+
var contentTargetDismissalDtoSchema = z27.object({
|
|
4196
|
+
targetRef: z27.string(),
|
|
4197
|
+
addressedUrl: z27.string().nullable(),
|
|
4198
|
+
note: z27.string().nullable(),
|
|
4199
|
+
dismissedAt: z27.string()
|
|
4147
4200
|
});
|
|
4148
|
-
var contentTargetDismissalsResponseDtoSchema =
|
|
4149
|
-
dismissals:
|
|
4201
|
+
var contentTargetDismissalsResponseDtoSchema = z27.object({
|
|
4202
|
+
dismissals: z27.array(contentTargetDismissalDtoSchema)
|
|
4150
4203
|
});
|
|
4151
|
-
var contentTargetDismissRequestSchema =
|
|
4152
|
-
targetRef:
|
|
4204
|
+
var contentTargetDismissRequestSchema = z27.object({
|
|
4205
|
+
targetRef: z27.string().min(1),
|
|
4153
4206
|
/** URL of the page the user wrote that addresses this recommendation. Stored verbatim for the audit trail; not currently used to suppress the slug-token matcher. */
|
|
4154
|
-
addressedUrl:
|
|
4207
|
+
addressedUrl: z27.string().url().optional(),
|
|
4155
4208
|
/** Free-form note (e.g. "covered in our Q1 content sprint"). 500 char cap is the API surface limit; the DB column is unbounded. */
|
|
4156
|
-
note:
|
|
4209
|
+
note: z27.string().max(500).optional()
|
|
4157
4210
|
});
|
|
4158
|
-
var recommendationExplanationDtoSchema =
|
|
4159
|
-
targetRef:
|
|
4211
|
+
var recommendationExplanationDtoSchema = z27.object({
|
|
4212
|
+
targetRef: z27.string(),
|
|
4160
4213
|
/** Version of the prompt template used. Bumping the version invalidates the cache forward without touching the table. */
|
|
4161
|
-
promptVersion:
|
|
4214
|
+
promptVersion: z27.string(),
|
|
4162
4215
|
/** Provider that produced the explanation (e.g. "claude", "gemini"). */
|
|
4163
|
-
provider:
|
|
4216
|
+
provider: z27.string(),
|
|
4164
4217
|
/** Model id within that provider (e.g. "claude-sonnet-4-6"). */
|
|
4165
|
-
model:
|
|
4218
|
+
model: z27.string(),
|
|
4166
4219
|
/** Markdown-formatted rationale + recommended next steps. */
|
|
4167
|
-
responseText:
|
|
4220
|
+
responseText: z27.string(),
|
|
4168
4221
|
/** Estimated cost in millicents (1/100 of a cent). 0 when unknown. */
|
|
4169
|
-
costMillicents:
|
|
4170
|
-
generatedAt:
|
|
4222
|
+
costMillicents: z27.number().int().nonnegative(),
|
|
4223
|
+
generatedAt: z27.string()
|
|
4171
4224
|
});
|
|
4172
|
-
var recommendationExplainRequestSchema =
|
|
4225
|
+
var recommendationExplainRequestSchema = z27.object({
|
|
4173
4226
|
/**
|
|
4174
4227
|
* Optional provider override (e.g. "claude" to force Claude even if
|
|
4175
4228
|
* the project's default is Gemini). Falls through to project default
|
|
4176
4229
|
* → auto-detect when omitted.
|
|
4177
4230
|
*/
|
|
4178
|
-
provider:
|
|
4231
|
+
provider: z27.string().optional(),
|
|
4179
4232
|
/**
|
|
4180
4233
|
* Optional model override within the chosen provider. Falls through to
|
|
4181
4234
|
* the `analyze`-tier default model when omitted.
|
|
4182
4235
|
*/
|
|
4183
|
-
model:
|
|
4236
|
+
model: z27.string().optional(),
|
|
4184
4237
|
/**
|
|
4185
4238
|
* Force a fresh LLM call even if a cached explanation exists for the
|
|
4186
4239
|
* current prompt version. Use sparingly — defeats the cache.
|
|
4187
4240
|
*/
|
|
4188
|
-
forceRefresh:
|
|
4241
|
+
forceRefresh: z27.boolean().optional()
|
|
4189
4242
|
});
|
|
4190
|
-
var contentBriefDtoSchema =
|
|
4243
|
+
var contentBriefDtoSchema = z27.object({
|
|
4191
4244
|
/** The query the brief is for (echoed from the recommendation). */
|
|
4192
|
-
targetQuery:
|
|
4245
|
+
targetQuery: z27.string().trim().min(1),
|
|
4193
4246
|
/** Always `ownable` in practice — the gate rejects `ceded` before synthesis. */
|
|
4194
4247
|
winnabilityClass: winnabilityClassSchema,
|
|
4195
4248
|
/** The differentiated content angle to take. */
|
|
4196
|
-
angle:
|
|
4249
|
+
angle: z27.string().trim().min(1),
|
|
4197
4250
|
/** Why this query is winnable, citing the cited-surface signal. */
|
|
4198
|
-
whyWinnable:
|
|
4251
|
+
whyWinnable: z27.string().trim().min(1),
|
|
4199
4252
|
/** The schema.org type or markup to add or extend. */
|
|
4200
|
-
schemaHookup:
|
|
4253
|
+
schemaHookup: z27.string().trim().min(1),
|
|
4201
4254
|
/** Why the cited surface is controllable (the ownable-vs-ceded reasoning). */
|
|
4202
|
-
controllableSurfaceRationale:
|
|
4255
|
+
controllableSurfaceRationale: z27.string().trim().min(1)
|
|
4203
4256
|
});
|
|
4204
|
-
var recommendationBriefDtoSchema =
|
|
4205
|
-
targetRef:
|
|
4257
|
+
var recommendationBriefDtoSchema = z27.object({
|
|
4258
|
+
targetRef: z27.string(),
|
|
4206
4259
|
/** Version of the brief prompt template; bumping invalidates the cache forward. */
|
|
4207
|
-
promptVersion:
|
|
4208
|
-
provider:
|
|
4209
|
-
model:
|
|
4260
|
+
promptVersion: z27.string(),
|
|
4261
|
+
provider: z27.string(),
|
|
4262
|
+
model: z27.string(),
|
|
4210
4263
|
brief: contentBriefDtoSchema,
|
|
4211
4264
|
/** Estimated cost in millicents (1/100 of a cent). 0 when unknown. */
|
|
4212
|
-
costMillicents:
|
|
4213
|
-
generatedAt:
|
|
4265
|
+
costMillicents: z27.number().int().nonnegative(),
|
|
4266
|
+
generatedAt: z27.string()
|
|
4214
4267
|
});
|
|
4215
|
-
var domainClassificationDtoSchema =
|
|
4216
|
-
domain:
|
|
4268
|
+
var domainClassificationDtoSchema = z27.object({
|
|
4269
|
+
domain: z27.string(),
|
|
4217
4270
|
competitorType: discoveryCompetitorTypeSchema,
|
|
4218
|
-
hits:
|
|
4219
|
-
updatedAt:
|
|
4220
|
-
});
|
|
4221
|
-
var domainClassificationsResponseDtoSchema = z26.object({
|
|
4222
|
-
classifications: z26.array(domainClassificationDtoSchema)
|
|
4271
|
+
hits: z27.number().int().nonnegative(),
|
|
4272
|
+
updatedAt: z27.string()
|
|
4223
4273
|
});
|
|
4224
|
-
var
|
|
4225
|
-
|
|
4226
|
-
title: z26.string(),
|
|
4227
|
-
domain: z26.string(),
|
|
4228
|
-
isOurDomain: z26.boolean(),
|
|
4229
|
-
isCompetitor: z26.boolean(),
|
|
4230
|
-
citationCount: z26.number().int().nonnegative(),
|
|
4231
|
-
providers: z26.array(providerNameSchema)
|
|
4232
|
-
});
|
|
4233
|
-
var contentSourceRowDtoSchema = z26.object({
|
|
4234
|
-
query: z26.string(),
|
|
4235
|
-
groundingSources: z26.array(contentGroundingSourceSchema)
|
|
4236
|
-
});
|
|
4237
|
-
var contentSourcesResponseDtoSchema = z26.object({
|
|
4238
|
-
sources: z26.array(contentSourceRowDtoSchema),
|
|
4239
|
-
latestRunId: z26.string()
|
|
4240
|
-
});
|
|
4241
|
-
var contentGapRowDtoSchema = z26.object({
|
|
4242
|
-
query: z26.string(),
|
|
4243
|
-
competitorDomains: z26.array(z26.string()),
|
|
4244
|
-
competitorCount: z26.number().int().nonnegative(),
|
|
4245
|
-
missRate: z26.number().min(0).max(1),
|
|
4246
|
-
lastSeenInRunId: z26.string()
|
|
4274
|
+
var domainClassificationsResponseDtoSchema = z27.object({
|
|
4275
|
+
classifications: z27.array(domainClassificationDtoSchema)
|
|
4247
4276
|
});
|
|
4248
|
-
var
|
|
4249
|
-
|
|
4250
|
-
|
|
4277
|
+
var contentGroundingSourceSchema = z27.object({
|
|
4278
|
+
uri: z27.string(),
|
|
4279
|
+
title: z27.string(),
|
|
4280
|
+
domain: z27.string(),
|
|
4281
|
+
isOurDomain: z27.boolean(),
|
|
4282
|
+
isCompetitor: z27.boolean(),
|
|
4283
|
+
citationCount: z27.number().int().nonnegative(),
|
|
4284
|
+
providers: z27.array(providerNameSchema)
|
|
4285
|
+
});
|
|
4286
|
+
var contentSourceRowDtoSchema = z27.object({
|
|
4287
|
+
query: z27.string(),
|
|
4288
|
+
groundingSources: z27.array(contentGroundingSourceSchema)
|
|
4289
|
+
});
|
|
4290
|
+
var contentSourcesResponseDtoSchema = z27.object({
|
|
4291
|
+
sources: z27.array(contentSourceRowDtoSchema),
|
|
4292
|
+
latestRunId: z27.string()
|
|
4293
|
+
});
|
|
4294
|
+
var contentGapRowDtoSchema = z27.object({
|
|
4295
|
+
query: z27.string(),
|
|
4296
|
+
competitorDomains: z27.array(z27.string()),
|
|
4297
|
+
competitorCount: z27.number().int().nonnegative(),
|
|
4298
|
+
missRate: z27.number().min(0).max(1),
|
|
4299
|
+
lastSeenInRunId: z27.string()
|
|
4300
|
+
});
|
|
4301
|
+
var contentGapsResponseDtoSchema = z27.object({
|
|
4302
|
+
gaps: z27.array(contentGapRowDtoSchema),
|
|
4303
|
+
latestRunId: z27.string()
|
|
4251
4304
|
});
|
|
4252
4305
|
|
|
4253
4306
|
// ../contracts/src/doctor.ts
|
|
4254
|
-
import { z as
|
|
4255
|
-
var checkStatusSchema =
|
|
4307
|
+
import { z as z28 } from "zod";
|
|
4308
|
+
var checkStatusSchema = z28.enum(["ok", "warn", "fail", "skipped"]);
|
|
4256
4309
|
var CheckStatuses = checkStatusSchema.enum;
|
|
4257
|
-
var checkScopeSchema =
|
|
4310
|
+
var checkScopeSchema = z28.enum(["global", "project"]);
|
|
4258
4311
|
var CheckScopes = checkScopeSchema.enum;
|
|
4259
|
-
var checkCategorySchema =
|
|
4312
|
+
var checkCategorySchema = z28.enum([
|
|
4260
4313
|
"auth",
|
|
4261
4314
|
"config",
|
|
4262
4315
|
"providers",
|
|
@@ -4267,31 +4320,31 @@ var checkCategorySchema = z27.enum([
|
|
|
4267
4320
|
"agent"
|
|
4268
4321
|
]);
|
|
4269
4322
|
var CheckCategories = checkCategorySchema.enum;
|
|
4270
|
-
var checkResultSchema =
|
|
4271
|
-
id:
|
|
4323
|
+
var checkResultSchema = z28.object({
|
|
4324
|
+
id: z28.string(),
|
|
4272
4325
|
category: checkCategorySchema,
|
|
4273
4326
|
scope: checkScopeSchema,
|
|
4274
|
-
title:
|
|
4327
|
+
title: z28.string(),
|
|
4275
4328
|
status: checkStatusSchema,
|
|
4276
|
-
code:
|
|
4277
|
-
summary:
|
|
4278
|
-
remediation:
|
|
4279
|
-
details:
|
|
4280
|
-
durationMs:
|
|
4329
|
+
code: z28.string().describe('Stable machine-readable code (e.g. "google.token.refresh-failed"). Use this for filtering and remediation logic.'),
|
|
4330
|
+
summary: z28.string(),
|
|
4331
|
+
remediation: z28.string().nullable().optional().describe('Operator-facing next step. Null when status is "ok" or no specific remediation applies.'),
|
|
4332
|
+
details: z28.record(z28.string(), z28.unknown()).optional().describe("Structured context \u2014 principal email, redirect URI, missing scopes, etc. Stable per check id."),
|
|
4333
|
+
durationMs: z28.number().int().nonnegative().describe("How long the check took to execute.")
|
|
4281
4334
|
});
|
|
4282
|
-
var doctorReportSchema =
|
|
4335
|
+
var doctorReportSchema = z28.object({
|
|
4283
4336
|
scope: checkScopeSchema,
|
|
4284
|
-
project:
|
|
4285
|
-
generatedAt:
|
|
4286
|
-
durationMs:
|
|
4287
|
-
summary:
|
|
4288
|
-
total:
|
|
4289
|
-
ok:
|
|
4290
|
-
warn:
|
|
4291
|
-
fail:
|
|
4292
|
-
skipped:
|
|
4337
|
+
project: z28.string().nullable().describe('Project name when scope is "project", null otherwise.'),
|
|
4338
|
+
generatedAt: z28.string().describe("ISO-8601 timestamp when this doctor run started."),
|
|
4339
|
+
durationMs: z28.number().int().nonnegative(),
|
|
4340
|
+
summary: z28.object({
|
|
4341
|
+
total: z28.number().int().nonnegative(),
|
|
4342
|
+
ok: z28.number().int().nonnegative(),
|
|
4343
|
+
warn: z28.number().int().nonnegative(),
|
|
4344
|
+
fail: z28.number().int().nonnegative(),
|
|
4345
|
+
skipped: z28.number().int().nonnegative()
|
|
4293
4346
|
}),
|
|
4294
|
-
checks:
|
|
4347
|
+
checks: z28.array(checkResultSchema)
|
|
4295
4348
|
});
|
|
4296
4349
|
function summarizeCheckResults(results) {
|
|
4297
4350
|
const summary = { total: results.length, ok: 0, warn: 0, fail: 0, skipped: 0 };
|
|
@@ -4320,52 +4373,52 @@ function normalizeQueryText(value) {
|
|
|
4320
4373
|
}
|
|
4321
4374
|
|
|
4322
4375
|
// ../contracts/src/citations.ts
|
|
4323
|
-
import { z as
|
|
4324
|
-
var citationCoverageProviderSchema =
|
|
4325
|
-
provider:
|
|
4376
|
+
import { z as z29 } from "zod";
|
|
4377
|
+
var citationCoverageProviderSchema = z29.object({
|
|
4378
|
+
provider: z29.string(),
|
|
4326
4379
|
citationState: citationStateSchema,
|
|
4327
|
-
cited:
|
|
4328
|
-
mentioned:
|
|
4329
|
-
runId:
|
|
4330
|
-
runCreatedAt:
|
|
4331
|
-
});
|
|
4332
|
-
var citationCoverageRowSchema =
|
|
4333
|
-
queryId:
|
|
4334
|
-
query:
|
|
4335
|
-
providers:
|
|
4336
|
-
citedCount:
|
|
4337
|
-
mentionedCount:
|
|
4338
|
-
totalProviders:
|
|
4339
|
-
});
|
|
4340
|
-
var competitorGapRowSchema =
|
|
4341
|
-
queryId:
|
|
4342
|
-
query:
|
|
4343
|
-
provider:
|
|
4344
|
-
citingCompetitors:
|
|
4345
|
-
runId:
|
|
4346
|
-
runCreatedAt:
|
|
4347
|
-
});
|
|
4348
|
-
var citationVisibilitySummarySchema =
|
|
4349
|
-
providersConfigured:
|
|
4350
|
-
providersCiting:
|
|
4351
|
-
providersMentioning:
|
|
4352
|
-
totalQueries:
|
|
4380
|
+
cited: z29.boolean(),
|
|
4381
|
+
mentioned: z29.boolean(),
|
|
4382
|
+
runId: z29.string(),
|
|
4383
|
+
runCreatedAt: z29.string()
|
|
4384
|
+
});
|
|
4385
|
+
var citationCoverageRowSchema = z29.object({
|
|
4386
|
+
queryId: z29.string(),
|
|
4387
|
+
query: z29.string(),
|
|
4388
|
+
providers: z29.array(citationCoverageProviderSchema),
|
|
4389
|
+
citedCount: z29.number().int().nonnegative(),
|
|
4390
|
+
mentionedCount: z29.number().int().nonnegative(),
|
|
4391
|
+
totalProviders: z29.number().int().nonnegative()
|
|
4392
|
+
});
|
|
4393
|
+
var competitorGapRowSchema = z29.object({
|
|
4394
|
+
queryId: z29.string(),
|
|
4395
|
+
query: z29.string(),
|
|
4396
|
+
provider: z29.string(),
|
|
4397
|
+
citingCompetitors: z29.array(z29.string()),
|
|
4398
|
+
runId: z29.string(),
|
|
4399
|
+
runCreatedAt: z29.string()
|
|
4400
|
+
});
|
|
4401
|
+
var citationVisibilitySummarySchema = z29.object({
|
|
4402
|
+
providersConfigured: z29.number().int().nonnegative(),
|
|
4403
|
+
providersCiting: z29.number().int().nonnegative(),
|
|
4404
|
+
providersMentioning: z29.number().int().nonnegative(),
|
|
4405
|
+
totalQueries: z29.number().int().nonnegative(),
|
|
4353
4406
|
// Cross-tab buckets — each tracked query with at least one snapshot lands
|
|
4354
4407
|
// in exactly one of these. Queries with zero snapshots are not counted in
|
|
4355
4408
|
// any bucket; (sum of buckets) ≤ totalQueries.
|
|
4356
|
-
queriesCitedAndMentioned:
|
|
4357
|
-
queriesCitedOnly:
|
|
4358
|
-
queriesMentionedOnly:
|
|
4359
|
-
queriesInvisible:
|
|
4360
|
-
latestRunId:
|
|
4361
|
-
latestRunAt:
|
|
4362
|
-
});
|
|
4363
|
-
var citationVisibilityResponseSchema =
|
|
4409
|
+
queriesCitedAndMentioned: z29.number().int().nonnegative(),
|
|
4410
|
+
queriesCitedOnly: z29.number().int().nonnegative(),
|
|
4411
|
+
queriesMentionedOnly: z29.number().int().nonnegative(),
|
|
4412
|
+
queriesInvisible: z29.number().int().nonnegative(),
|
|
4413
|
+
latestRunId: z29.string().nullable(),
|
|
4414
|
+
latestRunAt: z29.string().nullable()
|
|
4415
|
+
});
|
|
4416
|
+
var citationVisibilityResponseSchema = z29.object({
|
|
4364
4417
|
summary: citationVisibilitySummarySchema,
|
|
4365
|
-
byQuery:
|
|
4366
|
-
competitorGaps:
|
|
4367
|
-
status:
|
|
4368
|
-
reason:
|
|
4418
|
+
byQuery: z29.array(citationCoverageRowSchema),
|
|
4419
|
+
competitorGaps: z29.array(competitorGapRowSchema),
|
|
4420
|
+
status: z29.enum(["ready", "no-data"]),
|
|
4421
|
+
reason: z29.enum(["no-runs-yet", "no-queries"]).optional()
|
|
4369
4422
|
});
|
|
4370
4423
|
function emptyCitationVisibility(reason) {
|
|
4371
4424
|
return {
|
|
@@ -4392,10 +4445,10 @@ function citationStateToCited(state) {
|
|
|
4392
4445
|
}
|
|
4393
4446
|
|
|
4394
4447
|
// ../contracts/src/report.ts
|
|
4395
|
-
import { z as
|
|
4448
|
+
import { z as z30 } from "zod";
|
|
4396
4449
|
var REPORT_PERIOD_OPTIONS = [7, 14, 30, 90];
|
|
4397
4450
|
var REPORT_DEFAULT_PERIOD_DAYS = 30;
|
|
4398
|
-
var reportPeriodSchema =
|
|
4451
|
+
var reportPeriodSchema = z30.union([z30.literal(7), z30.literal(14), z30.literal(30), z30.literal(90)]).describe("Report window in days (7, 14, 30, or 90). Defaults to 30 when omitted.");
|
|
4399
4452
|
function isReportPeriodDays(n) {
|
|
4400
4453
|
return REPORT_PERIOD_OPTIONS.includes(n);
|
|
4401
4454
|
}
|
|
@@ -4410,45 +4463,45 @@ function parseReportPeriodDays(value) {
|
|
|
4410
4463
|
function reportComparisonWindowDays(periodDays) {
|
|
4411
4464
|
return Math.max(1, Math.floor(periodDays / 2));
|
|
4412
4465
|
}
|
|
4413
|
-
var providerLocationTreatmentSchema =
|
|
4466
|
+
var providerLocationTreatmentSchema = z30.enum([
|
|
4414
4467
|
"prompt",
|
|
4415
4468
|
"request-param",
|
|
4416
4469
|
"browser-geo",
|
|
4417
4470
|
"ignored"
|
|
4418
4471
|
]);
|
|
4419
|
-
var reportMetaLocationSchema =
|
|
4472
|
+
var reportMetaLocationSchema = z30.object({
|
|
4420
4473
|
/** Human-readable label as configured on the project (e.g. "michigan"). */
|
|
4421
|
-
label:
|
|
4474
|
+
label: z30.string(),
|
|
4422
4475
|
/** Resolved city/region/country from the project's `LocationContext`. */
|
|
4423
|
-
city:
|
|
4424
|
-
region:
|
|
4425
|
-
country:
|
|
4476
|
+
city: z30.string(),
|
|
4477
|
+
region: z30.string(),
|
|
4478
|
+
country: z30.string(),
|
|
4426
4479
|
/**
|
|
4427
4480
|
* Other locations configured on the project that did NOT power this report.
|
|
4428
4481
|
* When non-empty, callers should make clear that the report is location-scoped:
|
|
4429
4482
|
* a separate sweep is needed to see how AI engines respond from each one.
|
|
4430
4483
|
*/
|
|
4431
|
-
otherConfiguredLabels:
|
|
4484
|
+
otherConfiguredLabels: z30.array(z30.string())
|
|
4432
4485
|
});
|
|
4433
|
-
var reportProviderLocationHandlingSchema =
|
|
4486
|
+
var reportProviderLocationHandlingSchema = z30.object({
|
|
4434
4487
|
/** Provider name (matches `query_snapshots.provider`). */
|
|
4435
|
-
provider:
|
|
4488
|
+
provider: z30.string(),
|
|
4436
4489
|
/** How this provider applied the configured location during this run. */
|
|
4437
4490
|
treatment: providerLocationTreatmentSchema,
|
|
4438
4491
|
/** One-sentence explanation suitable for the report. */
|
|
4439
|
-
description:
|
|
4492
|
+
description: z30.string()
|
|
4440
4493
|
});
|
|
4441
|
-
var reportMetaSchema =
|
|
4494
|
+
var reportMetaSchema = z30.object({
|
|
4442
4495
|
/** ISO timestamp the report was generated (server clock). */
|
|
4443
|
-
generatedAt:
|
|
4496
|
+
generatedAt: z30.string(),
|
|
4444
4497
|
/** Project the report covers. */
|
|
4445
|
-
project:
|
|
4446
|
-
id:
|
|
4447
|
-
name:
|
|
4448
|
-
displayName:
|
|
4449
|
-
canonicalDomain:
|
|
4450
|
-
country:
|
|
4451
|
-
language:
|
|
4498
|
+
project: z30.object({
|
|
4499
|
+
id: z30.string(),
|
|
4500
|
+
name: z30.string(),
|
|
4501
|
+
displayName: z30.string(),
|
|
4502
|
+
canonicalDomain: z30.string(),
|
|
4503
|
+
country: z30.string(),
|
|
4504
|
+
language: z30.string()
|
|
4452
4505
|
}),
|
|
4453
4506
|
/**
|
|
4454
4507
|
* The location that powered the latest visibility run, when one was set.
|
|
@@ -4463,31 +4516,31 @@ var reportMetaSchema = z29.object({
|
|
|
4463
4516
|
* each provider's answer — some providers append it to the prompt, some
|
|
4464
4517
|
* pass it as a structured request field, and some (CDP) ignore it.
|
|
4465
4518
|
*/
|
|
4466
|
-
providerLocationHandling:
|
|
4519
|
+
providerLocationHandling: z30.array(reportProviderLocationHandlingSchema),
|
|
4467
4520
|
/** Earliest data point referenced by the report (ISO date). */
|
|
4468
|
-
periodStart:
|
|
4521
|
+
periodStart: z30.string().nullable(),
|
|
4469
4522
|
/** Latest data point referenced by the report (ISO date). */
|
|
4470
|
-
periodEnd:
|
|
4523
|
+
periodEnd: z30.string().nullable(),
|
|
4471
4524
|
/**
|
|
4472
4525
|
* The selected report window, in days (one of `REPORT_PERIOD_OPTIONS`).
|
|
4473
4526
|
* Every time-windowed section scopes to this many days; renderers read it to
|
|
4474
4527
|
* label the window ("Last 30 days", "(30d)"). Defaults to
|
|
4475
4528
|
* `REPORT_DEFAULT_PERIOD_DAYS` when no `period` is requested.
|
|
4476
4529
|
*/
|
|
4477
|
-
periodDays:
|
|
4530
|
+
periodDays: z30.number().int().positive()
|
|
4478
4531
|
});
|
|
4479
|
-
var reportExecutiveSummarySchema =
|
|
4532
|
+
var reportExecutiveSummarySchema = z30.object({
|
|
4480
4533
|
/**
|
|
4481
4534
|
* 0..100 — share of tracked queries that were cited by at least one
|
|
4482
4535
|
* provider in the latest run. "Cited" means the project's domain appeared
|
|
4483
4536
|
* in the source list / grounding the AI used to answer. Computed per-query
|
|
4484
4537
|
* (not per-(query × provider)) so the rate is invariant to provider count.
|
|
4485
4538
|
*/
|
|
4486
|
-
citationRate:
|
|
4539
|
+
citationRate: z30.number(),
|
|
4487
4540
|
/** Numerator of `citationRate` — distinct tracked queries cited by ≥1 provider in the latest run. */
|
|
4488
|
-
citedQueryCount:
|
|
4541
|
+
citedQueryCount: z30.number(),
|
|
4489
4542
|
/** Denominator of `citationRate` — total tracked queries. */
|
|
4490
|
-
totalQueryCount:
|
|
4543
|
+
totalQueryCount: z30.number(),
|
|
4491
4544
|
/**
|
|
4492
4545
|
* 0..100 — share of tracked queries where the project's brand or domain
|
|
4493
4546
|
* appeared in at least one provider's answer text in the latest run.
|
|
@@ -4495,71 +4548,71 @@ var reportExecutiveSummarySchema = z29.object({
|
|
|
4495
4548
|
* the prose without citing your domain in its sources, and vice versa.
|
|
4496
4549
|
* Same per-query denominator as `citationRate` for consistency.
|
|
4497
4550
|
*/
|
|
4498
|
-
mentionRate:
|
|
4551
|
+
mentionRate: z30.number(),
|
|
4499
4552
|
/** Numerator of `mentionRate` — distinct tracked queries mentioned in ≥1 provider's answer text. */
|
|
4500
|
-
mentionedQueryCount:
|
|
4553
|
+
mentionedQueryCount: z30.number(),
|
|
4501
4554
|
/** Compared to the previous run: 'up' | 'down' | 'flat' | 'unknown' (no prior run). */
|
|
4502
|
-
trend:
|
|
4555
|
+
trend: z30.enum(["up", "down", "flat", "unknown"]),
|
|
4503
4556
|
/** Total tracked queries. */
|
|
4504
|
-
queryCount:
|
|
4557
|
+
queryCount: z30.number(),
|
|
4505
4558
|
/** Total tracked competitors. */
|
|
4506
|
-
competitorCount:
|
|
4559
|
+
competitorCount: z30.number(),
|
|
4507
4560
|
/** Number of providers in the latest run. */
|
|
4508
|
-
providerCount:
|
|
4561
|
+
providerCount: z30.number(),
|
|
4509
4562
|
/** GSC totals across the most-recent sync window. Null when GSC is not connected. */
|
|
4510
|
-
gsc:
|
|
4511
|
-
clicks:
|
|
4512
|
-
impressions:
|
|
4513
|
-
ctr:
|
|
4514
|
-
avgPosition:
|
|
4515
|
-
periodStart:
|
|
4516
|
-
periodEnd:
|
|
4563
|
+
gsc: z30.object({
|
|
4564
|
+
clicks: z30.number(),
|
|
4565
|
+
impressions: z30.number(),
|
|
4566
|
+
ctr: z30.number(),
|
|
4567
|
+
avgPosition: z30.number(),
|
|
4568
|
+
periodStart: z30.string(),
|
|
4569
|
+
periodEnd: z30.string()
|
|
4517
4570
|
}).nullable(),
|
|
4518
4571
|
/** GA4 totals across the most-recent sync period. Null when GA4 is not connected. */
|
|
4519
|
-
ga:
|
|
4520
|
-
sessions:
|
|
4521
|
-
users:
|
|
4522
|
-
periodStart:
|
|
4523
|
-
periodEnd:
|
|
4572
|
+
ga: z30.object({
|
|
4573
|
+
sessions: z30.number(),
|
|
4574
|
+
users: z30.number(),
|
|
4575
|
+
periodStart: z30.string(),
|
|
4576
|
+
periodEnd: z30.string()
|
|
4524
4577
|
}).nullable(),
|
|
4525
4578
|
/** Top 3-5 findings, each rendered as a single-sentence narrative. */
|
|
4526
|
-
findings:
|
|
4527
|
-
title:
|
|
4528
|
-
detail:
|
|
4529
|
-
tone:
|
|
4579
|
+
findings: z30.array(z30.object({
|
|
4580
|
+
title: z30.string(),
|
|
4581
|
+
detail: z30.string(),
|
|
4582
|
+
tone: z30.enum(["positive", "caution", "negative", "neutral"])
|
|
4530
4583
|
}))
|
|
4531
4584
|
});
|
|
4532
|
-
var citationCellSchema =
|
|
4533
|
-
citationState:
|
|
4534
|
-
answerMentioned:
|
|
4535
|
-
model:
|
|
4585
|
+
var citationCellSchema = z30.object({
|
|
4586
|
+
citationState: z30.enum(["cited", "not-cited", "pending"]),
|
|
4587
|
+
answerMentioned: z30.boolean().nullable(),
|
|
4588
|
+
model: z30.string().nullable()
|
|
4536
4589
|
});
|
|
4537
|
-
var citationScorecardSchema =
|
|
4538
|
-
queries:
|
|
4539
|
-
providers:
|
|
4590
|
+
var citationScorecardSchema = z30.object({
|
|
4591
|
+
queries: z30.array(z30.string()),
|
|
4592
|
+
providers: z30.array(z30.string()),
|
|
4540
4593
|
/** matrix[queryIndex][providerIndex] — null when no snapshot exists for the pair. */
|
|
4541
|
-
matrix:
|
|
4594
|
+
matrix: z30.array(z30.array(citationCellSchema.nullable())),
|
|
4542
4595
|
/** Per-provider citation + mention rates (0..100). */
|
|
4543
|
-
providerRates:
|
|
4544
|
-
provider:
|
|
4545
|
-
citedCount:
|
|
4596
|
+
providerRates: z30.array(z30.object({
|
|
4597
|
+
provider: z30.string(),
|
|
4598
|
+
citedCount: z30.number(),
|
|
4546
4599
|
/** Number of snapshots for this provider where the answer text mentioned the project. */
|
|
4547
|
-
mentionedCount:
|
|
4548
|
-
totalCount:
|
|
4549
|
-
citationRate:
|
|
4550
|
-
mentionRate:
|
|
4600
|
+
mentionedCount: z30.number(),
|
|
4601
|
+
totalCount: z30.number(),
|
|
4602
|
+
citationRate: z30.number(),
|
|
4603
|
+
mentionRate: z30.number()
|
|
4551
4604
|
}))
|
|
4552
4605
|
});
|
|
4553
|
-
var competitorRowSchema =
|
|
4554
|
-
domain:
|
|
4606
|
+
var competitorRowSchema = z30.object({
|
|
4607
|
+
domain: z30.string(),
|
|
4555
4608
|
/** Number of (query × provider) pairs that cited this competitor. */
|
|
4556
|
-
citationCount:
|
|
4609
|
+
citationCount: z30.number(),
|
|
4557
4610
|
/** Out-of count for the same denominator. */
|
|
4558
|
-
totalCount:
|
|
4611
|
+
totalCount: z30.number(),
|
|
4559
4612
|
/** 'High' | 'Moderate' | 'Low' | 'None' — from buildPortfolioProject pressure logic. */
|
|
4560
|
-
pressureLabel:
|
|
4613
|
+
pressureLabel: z30.enum(["High", "Moderate", "Low", "None"]),
|
|
4561
4614
|
/** Distinct queries on which this competitor was cited. */
|
|
4562
|
-
citedQueries:
|
|
4615
|
+
citedQueries: z30.array(z30.string()),
|
|
4563
4616
|
/**
|
|
4564
4617
|
* Citation share 0..100. Numerator = this competitor's `citationCount`.
|
|
4565
4618
|
* Denominator = sum of `citationCount` across all competitors plus the
|
|
@@ -4567,30 +4620,30 @@ var competitorRowSchema = z29.object({
|
|
|
4567
4620
|
* slots in the snapshot. Distinct from the project-level Mention Share
|
|
4568
4621
|
* gauge — that one is brand-in-answer-text, this one is domain-in-source-list.
|
|
4569
4622
|
*/
|
|
4570
|
-
sharePct:
|
|
4623
|
+
sharePct: z30.number(),
|
|
4571
4624
|
/**
|
|
4572
4625
|
* URLs from the latest run's grounding sources whose host matches this
|
|
4573
4626
|
* competitor's domain, with the queries each URL was cited for. Empty
|
|
4574
4627
|
* when no grounding-source data is available (e.g. no `rawResponse` JSON
|
|
4575
4628
|
* stored for the snapshots).
|
|
4576
4629
|
*/
|
|
4577
|
-
theirCitedPages:
|
|
4630
|
+
theirCitedPages: z30.array(z30.object({ url: z30.string(), citedFor: z30.array(z30.string()) }))
|
|
4578
4631
|
});
|
|
4579
|
-
var competitorLandscapeSchema =
|
|
4632
|
+
var competitorLandscapeSchema = z30.object({
|
|
4580
4633
|
/** Project's own citation count (for the bar chart comparing project vs competitors). */
|
|
4581
|
-
projectCitationCount:
|
|
4582
|
-
competitors:
|
|
4634
|
+
projectCitationCount: z30.number(),
|
|
4635
|
+
competitors: z30.array(competitorRowSchema)
|
|
4583
4636
|
});
|
|
4584
|
-
var mentionRowSchema =
|
|
4585
|
-
domain:
|
|
4637
|
+
var mentionRowSchema = z30.object({
|
|
4638
|
+
domain: z30.string(),
|
|
4586
4639
|
/** Number of (query × provider) pairs whose answer text mentioned this competitor's brand or domain. */
|
|
4587
|
-
mentionCount:
|
|
4640
|
+
mentionCount: z30.number(),
|
|
4588
4641
|
/** Out-of count for the same denominator (snapshots that had answer text). */
|
|
4589
|
-
totalCount:
|
|
4642
|
+
totalCount: z30.number(),
|
|
4590
4643
|
/** 'High' | 'Moderate' | 'Low' | 'None' — mention frequency tier (mirrors CompetitorRow.pressureLabel). */
|
|
4591
|
-
pressureLabel:
|
|
4644
|
+
pressureLabel: z30.enum(["High", "Moderate", "Low", "None"]),
|
|
4592
4645
|
/** Distinct queries on which this competitor was mentioned. */
|
|
4593
|
-
mentionedQueries:
|
|
4646
|
+
mentionedQueries: z30.array(z30.string()),
|
|
4594
4647
|
/**
|
|
4595
4648
|
* Mention share 0..100. Numerator = this competitor's `mentionCount`.
|
|
4596
4649
|
* Denominator = sum of `mentionCount` across all competitors plus the
|
|
@@ -4598,135 +4651,135 @@ var mentionRowSchema = z29.object({
|
|
|
4598
4651
|
* mention. Per-competitor split of the same head-to-head measure the
|
|
4599
4652
|
* project's hero `MentionShareDto` gauge headlines.
|
|
4600
4653
|
*/
|
|
4601
|
-
sharePct:
|
|
4654
|
+
sharePct: z30.number()
|
|
4602
4655
|
});
|
|
4603
|
-
var mentionLandscapeSchema =
|
|
4656
|
+
var mentionLandscapeSchema = z30.object({
|
|
4604
4657
|
/** Project's own mention count (for the bar chart comparing project vs competitors). */
|
|
4605
|
-
projectMentionCount:
|
|
4658
|
+
projectMentionCount: z30.number(),
|
|
4606
4659
|
/** Snapshots considered — those with non-empty answerText. Drives the totalCount denominator. */
|
|
4607
|
-
totalAnswerSnapshots:
|
|
4608
|
-
competitors:
|
|
4660
|
+
totalAnswerSnapshots: z30.number(),
|
|
4661
|
+
competitors: z30.array(mentionRowSchema)
|
|
4609
4662
|
});
|
|
4610
|
-
var aiSourceCategoryBucketSchema =
|
|
4663
|
+
var aiSourceCategoryBucketSchema = z30.object({
|
|
4611
4664
|
/** Category slug from packages/contracts/src/source-categories. */
|
|
4612
|
-
category:
|
|
4665
|
+
category: z30.string(),
|
|
4613
4666
|
/** Display label. */
|
|
4614
|
-
label:
|
|
4667
|
+
label: z30.string(),
|
|
4615
4668
|
/** Number of citations falling in this category. */
|
|
4616
|
-
count:
|
|
4669
|
+
count: z30.number(),
|
|
4617
4670
|
/** 0..100 share of total citations. */
|
|
4618
|
-
sharePct:
|
|
4671
|
+
sharePct: z30.number()
|
|
4619
4672
|
});
|
|
4620
|
-
var aiSourceOriginSchema =
|
|
4621
|
-
categories:
|
|
4673
|
+
var aiSourceOriginSchema = z30.object({
|
|
4674
|
+
categories: z30.array(aiSourceCategoryBucketSchema),
|
|
4622
4675
|
/** Top 20 source domains by citation count (excluding the project's own domain). */
|
|
4623
|
-
topDomains:
|
|
4624
|
-
domain:
|
|
4625
|
-
count:
|
|
4676
|
+
topDomains: z30.array(z30.object({
|
|
4677
|
+
domain: z30.string(),
|
|
4678
|
+
count: z30.number(),
|
|
4626
4679
|
/** True when the domain is one of the project's tracked competitors. */
|
|
4627
|
-
isCompetitor:
|
|
4680
|
+
isCompetitor: z30.boolean()
|
|
4628
4681
|
}))
|
|
4629
4682
|
});
|
|
4630
|
-
var gscQueryRowSchema =
|
|
4631
|
-
query:
|
|
4632
|
-
clicks:
|
|
4633
|
-
impressions:
|
|
4634
|
-
ctr:
|
|
4635
|
-
avgPosition:
|
|
4683
|
+
var gscQueryRowSchema = z30.object({
|
|
4684
|
+
query: z30.string(),
|
|
4685
|
+
clicks: z30.number(),
|
|
4686
|
+
impressions: z30.number(),
|
|
4687
|
+
ctr: z30.number(),
|
|
4688
|
+
avgPosition: z30.number(),
|
|
4636
4689
|
/** Heuristic categorization: 'brand' | 'lead-gen' | 'industry' | 'other'. */
|
|
4637
|
-
category:
|
|
4638
|
-
});
|
|
4639
|
-
var gscSectionSchema =
|
|
4640
|
-
periodStart:
|
|
4641
|
-
periodEnd:
|
|
4642
|
-
totalClicks:
|
|
4643
|
-
totalImpressions:
|
|
4644
|
-
ctr:
|
|
4645
|
-
avgPosition:
|
|
4646
|
-
topQueries:
|
|
4647
|
-
categoryBreakdown:
|
|
4648
|
-
category:
|
|
4649
|
-
clicks:
|
|
4650
|
-
impressions:
|
|
4651
|
-
sharePct:
|
|
4690
|
+
category: z30.enum(["brand", "lead-gen", "industry", "other"])
|
|
4691
|
+
});
|
|
4692
|
+
var gscSectionSchema = z30.object({
|
|
4693
|
+
periodStart: z30.string(),
|
|
4694
|
+
periodEnd: z30.string(),
|
|
4695
|
+
totalClicks: z30.number(),
|
|
4696
|
+
totalImpressions: z30.number(),
|
|
4697
|
+
ctr: z30.number(),
|
|
4698
|
+
avgPosition: z30.number(),
|
|
4699
|
+
topQueries: z30.array(gscQueryRowSchema),
|
|
4700
|
+
categoryBreakdown: z30.array(z30.object({
|
|
4701
|
+
category: z30.enum(["brand", "lead-gen", "industry", "other"]),
|
|
4702
|
+
clicks: z30.number(),
|
|
4703
|
+
impressions: z30.number(),
|
|
4704
|
+
sharePct: z30.number()
|
|
4652
4705
|
})),
|
|
4653
|
-
trend:
|
|
4706
|
+
trend: z30.array(z30.object({ date: z30.string(), clicks: z30.number(), impressions: z30.number() })),
|
|
4654
4707
|
/**
|
|
4655
4708
|
* Tracked AEO queries that have no GSC impressions in the report window.
|
|
4656
4709
|
* Surfaces queries that may not represent real search demand.
|
|
4657
4710
|
*/
|
|
4658
|
-
trackedButNoGsc:
|
|
4711
|
+
trackedButNoGsc: z30.array(z30.string()),
|
|
4659
4712
|
/**
|
|
4660
4713
|
* GSC top queries (sorted by impressions desc) that are not tracked as
|
|
4661
4714
|
* AEO queries — the candidate set for adding to the AEO project.
|
|
4662
4715
|
*/
|
|
4663
|
-
gscButNotTracked:
|
|
4664
|
-
});
|
|
4665
|
-
var gaTrafficSectionSchema =
|
|
4666
|
-
totalSessions:
|
|
4667
|
-
totalUsers:
|
|
4668
|
-
totalOrganicSessions:
|
|
4669
|
-
periodStart:
|
|
4670
|
-
periodEnd:
|
|
4671
|
-
topLandingPages:
|
|
4672
|
-
page:
|
|
4673
|
-
sessions:
|
|
4674
|
-
users:
|
|
4675
|
-
organicSessions:
|
|
4716
|
+
gscButNotTracked: z30.array(z30.string())
|
|
4717
|
+
});
|
|
4718
|
+
var gaTrafficSectionSchema = z30.object({
|
|
4719
|
+
totalSessions: z30.number(),
|
|
4720
|
+
totalUsers: z30.number(),
|
|
4721
|
+
totalOrganicSessions: z30.number(),
|
|
4722
|
+
periodStart: z30.string(),
|
|
4723
|
+
periodEnd: z30.string(),
|
|
4724
|
+
topLandingPages: z30.array(z30.object({
|
|
4725
|
+
page: z30.string(),
|
|
4726
|
+
sessions: z30.number(),
|
|
4727
|
+
users: z30.number(),
|
|
4728
|
+
organicSessions: z30.number()
|
|
4676
4729
|
})),
|
|
4677
|
-
channelBreakdown:
|
|
4678
|
-
channel:
|
|
4679
|
-
sessions:
|
|
4680
|
-
sharePct:
|
|
4730
|
+
channelBreakdown: z30.array(z30.object({
|
|
4731
|
+
channel: z30.string(),
|
|
4732
|
+
sessions: z30.number(),
|
|
4733
|
+
sharePct: z30.number()
|
|
4681
4734
|
}))
|
|
4682
4735
|
});
|
|
4683
|
-
var socialReferralSectionSchema =
|
|
4684
|
-
totalSessions:
|
|
4685
|
-
organicSessions:
|
|
4686
|
-
paidSessions:
|
|
4687
|
-
channels:
|
|
4688
|
-
channelGroup:
|
|
4689
|
-
sessions:
|
|
4690
|
-
sharePct:
|
|
4736
|
+
var socialReferralSectionSchema = z30.object({
|
|
4737
|
+
totalSessions: z30.number(),
|
|
4738
|
+
organicSessions: z30.number(),
|
|
4739
|
+
paidSessions: z30.number(),
|
|
4740
|
+
channels: z30.array(z30.object({
|
|
4741
|
+
channelGroup: z30.string(),
|
|
4742
|
+
sessions: z30.number(),
|
|
4743
|
+
sharePct: z30.number()
|
|
4691
4744
|
})),
|
|
4692
|
-
topCampaigns:
|
|
4693
|
-
source:
|
|
4694
|
-
medium:
|
|
4695
|
-
sessions:
|
|
4745
|
+
topCampaigns: z30.array(z30.object({
|
|
4746
|
+
source: z30.string(),
|
|
4747
|
+
medium: z30.string(),
|
|
4748
|
+
sessions: z30.number()
|
|
4696
4749
|
}))
|
|
4697
4750
|
});
|
|
4698
|
-
var aiReferralSectionSchema =
|
|
4699
|
-
totalSessions:
|
|
4700
|
-
totalUsers:
|
|
4701
|
-
paidSessions:
|
|
4702
|
-
paidUsers:
|
|
4703
|
-
organicSessions:
|
|
4704
|
-
organicUsers:
|
|
4705
|
-
bySource:
|
|
4706
|
-
source:
|
|
4707
|
-
sessions:
|
|
4708
|
-
users:
|
|
4709
|
-
paidSessions:
|
|
4710
|
-
organicSessions:
|
|
4711
|
-
sharePct:
|
|
4751
|
+
var aiReferralSectionSchema = z30.object({
|
|
4752
|
+
totalSessions: z30.number(),
|
|
4753
|
+
totalUsers: z30.number(),
|
|
4754
|
+
paidSessions: z30.number(),
|
|
4755
|
+
paidUsers: z30.number(),
|
|
4756
|
+
organicSessions: z30.number(),
|
|
4757
|
+
organicUsers: z30.number(),
|
|
4758
|
+
bySource: z30.array(z30.object({
|
|
4759
|
+
source: z30.string(),
|
|
4760
|
+
sessions: z30.number(),
|
|
4761
|
+
users: z30.number(),
|
|
4762
|
+
paidSessions: z30.number(),
|
|
4763
|
+
organicSessions: z30.number(),
|
|
4764
|
+
sharePct: z30.number()
|
|
4712
4765
|
})),
|
|
4713
|
-
trend:
|
|
4714
|
-
topLandingPages:
|
|
4715
|
-
page:
|
|
4716
|
-
sessions:
|
|
4717
|
-
users:
|
|
4766
|
+
trend: z30.array(z30.object({ date: z30.string(), sessions: z30.number() })),
|
|
4767
|
+
topLandingPages: z30.array(z30.object({
|
|
4768
|
+
page: z30.string(),
|
|
4769
|
+
sessions: z30.number(),
|
|
4770
|
+
users: z30.number()
|
|
4718
4771
|
}))
|
|
4719
4772
|
});
|
|
4720
|
-
var serverActivitySectionSchema =
|
|
4773
|
+
var serverActivitySectionSchema = z30.object({
|
|
4721
4774
|
/** ISO8601 inclusive lower bound of the report window (default: 7 days). */
|
|
4722
|
-
windowStart:
|
|
4775
|
+
windowStart: z30.string(),
|
|
4723
4776
|
/** ISO8601 inclusive upper bound. */
|
|
4724
|
-
windowEnd:
|
|
4725
|
-
hasData:
|
|
4777
|
+
windowEnd: z30.string(),
|
|
4778
|
+
hasData: z30.boolean(),
|
|
4726
4779
|
/** Last-7d total verified crawler hits, with prior 7d for delta. */
|
|
4727
|
-
verifiedCrawlerHits:
|
|
4780
|
+
verifiedCrawlerHits: z30.object({ current: z30.number(), prior: z30.number(), deltaPct: z30.number().nullable() }),
|
|
4728
4781
|
/** Last-7d total unverified crawler hits, separated from verified trust metrics. */
|
|
4729
|
-
unverifiedCrawlerHits:
|
|
4782
|
+
unverifiedCrawlerHits: z30.object({ current: z30.number(), prior: z30.number(), deltaPct: z30.number().nullable() }),
|
|
4730
4783
|
/**
|
|
4731
4784
|
* Last-7d on-demand per-user fetches from AI surfaces (ChatGPT-User,
|
|
4732
4785
|
* Perplexity-User, MistralAI-User). Disjoint from `verifiedCrawlerHits` /
|
|
@@ -4735,9 +4788,9 @@ var serverActivitySectionSchema = z29.object({
|
|
|
4735
4788
|
* because the operational question for user-fetch is "is this happening?"
|
|
4736
4789
|
* not "is this a confirmed bot identity?"
|
|
4737
4790
|
*/
|
|
4738
|
-
aiUserFetchHits:
|
|
4791
|
+
aiUserFetchHits: z30.object({ current: z30.number(), prior: z30.number(), deltaPct: z30.number().nullable() }),
|
|
4739
4792
|
/** Last-7d AI-referral sessions (sessionized from server-side request evidence). Paid + organic + unclassified. */
|
|
4740
|
-
referralArrivals:
|
|
4793
|
+
referralArrivals: z30.object({ current: z30.number(), prior: z30.number(), deltaPct: z30.number().nullable() }),
|
|
4741
4794
|
/**
|
|
4742
4795
|
* `referralArrivals` split by traffic class. The three buckets sum to it.
|
|
4743
4796
|
*
|
|
@@ -4746,23 +4799,23 @@ var serverActivitySectionSchema = z29.object({
|
|
|
4746
4799
|
* never be resolved. Reporting them as organic would overstate earned AI
|
|
4747
4800
|
* traffic by exactly a client's ad volume.
|
|
4748
4801
|
*/
|
|
4749
|
-
referralArrivalsByClass:
|
|
4750
|
-
paid:
|
|
4751
|
-
organic:
|
|
4752
|
-
unclassified:
|
|
4802
|
+
referralArrivalsByClass: z30.object({
|
|
4803
|
+
paid: z30.object({ current: z30.number(), prior: z30.number(), deltaPct: z30.number().nullable() }),
|
|
4804
|
+
organic: z30.object({ current: z30.number(), prior: z30.number(), deltaPct: z30.number().nullable() }),
|
|
4805
|
+
unclassified: z30.object({ current: z30.number(), prior: z30.number(), deltaPct: z30.number().nullable() })
|
|
4753
4806
|
}),
|
|
4754
4807
|
/** Pre-rendered one-line breakdown, e.g. "Paid 1,200 · Organic 24". Empty when there is nothing to split. */
|
|
4755
|
-
referralArrivalsClassSummary:
|
|
4808
|
+
referralArrivalsClassSummary: z30.string(),
|
|
4756
4809
|
/** Per-AI-operator breakdown (OpenAI, Anthropic, Google AI, Perplexity, …). */
|
|
4757
|
-
byOperator:
|
|
4758
|
-
operator:
|
|
4759
|
-
verifiedHits:
|
|
4810
|
+
byOperator: z30.array(z30.object({
|
|
4811
|
+
operator: z30.string(),
|
|
4812
|
+
verifiedHits: z30.number(),
|
|
4760
4813
|
/** Shown to agency audience only: claimed-bot UA, source IP not in a published range. */
|
|
4761
|
-
unverifiedHits:
|
|
4814
|
+
unverifiedHits: z30.number(),
|
|
4762
4815
|
/** Per-user fetches from this operator's AI surface (ChatGPT-User, …). */
|
|
4763
|
-
userFetchHits:
|
|
4764
|
-
referralArrivals:
|
|
4765
|
-
deltaPct:
|
|
4816
|
+
userFetchHits: z30.number(),
|
|
4817
|
+
referralArrivals: z30.number(),
|
|
4818
|
+
deltaPct: z30.number().nullable()
|
|
4766
4819
|
})),
|
|
4767
4820
|
/**
|
|
4768
4821
|
* Top crawled paths (verified only, last-7d). Path-level citation cross-reference
|
|
@@ -4772,88 +4825,88 @@ var serverActivitySectionSchema = z29.object({
|
|
|
4772
4825
|
* citation evidence can extend this entry with a `citationState` field without
|
|
4773
4826
|
* breaking the contract.
|
|
4774
4827
|
*/
|
|
4775
|
-
topCrawledPaths:
|
|
4776
|
-
path:
|
|
4777
|
-
verifiedHits:
|
|
4828
|
+
topCrawledPaths: z30.array(z30.object({
|
|
4829
|
+
path: z30.string(),
|
|
4830
|
+
verifiedHits: z30.number(),
|
|
4778
4831
|
/** How many distinct AI operators crawled this path in the window. */
|
|
4779
|
-
distinctOperators:
|
|
4832
|
+
distinctOperators: z30.number()
|
|
4780
4833
|
})),
|
|
4781
4834
|
/** AI products that sent ≥1 session in the window (referral by destination). */
|
|
4782
|
-
referralProducts:
|
|
4783
|
-
product:
|
|
4784
|
-
arrivals:
|
|
4785
|
-
distinctLandingPaths:
|
|
4835
|
+
referralProducts: z30.array(z30.object({
|
|
4836
|
+
product: z30.string(),
|
|
4837
|
+
arrivals: z30.number(),
|
|
4838
|
+
distinctLandingPaths: z30.number()
|
|
4786
4839
|
})),
|
|
4787
4840
|
/** Daily trend, last 14d for sparkline / chart rendering. */
|
|
4788
|
-
dailyTrend:
|
|
4789
|
-
date:
|
|
4790
|
-
verifiedCrawlerHits:
|
|
4791
|
-
userFetchHits:
|
|
4792
|
-
referralArrivals:
|
|
4841
|
+
dailyTrend: z30.array(z30.object({
|
|
4842
|
+
date: z30.string(),
|
|
4843
|
+
verifiedCrawlerHits: z30.number(),
|
|
4844
|
+
userFetchHits: z30.number(),
|
|
4845
|
+
referralArrivals: z30.number()
|
|
4793
4846
|
})),
|
|
4794
4847
|
/**
|
|
4795
4848
|
* Top landing paths for AI-referral sessions (last-7d).
|
|
4796
4849
|
* Complements `topCrawledPaths` (what bots fetch) with what humans actually land on.
|
|
4797
4850
|
*/
|
|
4798
|
-
topReferralLandingPaths:
|
|
4799
|
-
path:
|
|
4800
|
-
arrivals:
|
|
4801
|
-
distinctProducts:
|
|
4851
|
+
topReferralLandingPaths: z30.array(z30.object({
|
|
4852
|
+
path: z30.string(),
|
|
4853
|
+
arrivals: z30.number(),
|
|
4854
|
+
distinctProducts: z30.number()
|
|
4802
4855
|
}))
|
|
4803
4856
|
});
|
|
4804
|
-
var indexingHealthSectionSchema =
|
|
4857
|
+
var indexingHealthSectionSchema = z30.object({
|
|
4805
4858
|
/** Source: 'google' | 'bing' | null when neither is connected. */
|
|
4806
|
-
provider:
|
|
4807
|
-
total:
|
|
4808
|
-
indexed:
|
|
4809
|
-
notIndexed:
|
|
4859
|
+
provider: z30.enum(["google", "bing"]).nullable(),
|
|
4860
|
+
total: z30.number(),
|
|
4861
|
+
indexed: z30.number(),
|
|
4862
|
+
notIndexed: z30.number(),
|
|
4810
4863
|
/** Google-only — pages explicitly marked as deindexed. Bing reports 'unknown' instead. */
|
|
4811
|
-
deindexed:
|
|
4864
|
+
deindexed: z30.number(),
|
|
4812
4865
|
/** Bing-only — pages with no inspection data yet. */
|
|
4813
|
-
unknown:
|
|
4866
|
+
unknown: z30.number(),
|
|
4814
4867
|
/** 0..100. */
|
|
4815
|
-
indexedPct:
|
|
4868
|
+
indexedPct: z30.number()
|
|
4816
4869
|
});
|
|
4817
|
-
var citationsTrendPointSchema =
|
|
4870
|
+
var citationsTrendPointSchema = z30.object({
|
|
4818
4871
|
/** Run ID — anchor for cross-section linking. */
|
|
4819
|
-
runId:
|
|
4872
|
+
runId: z30.string(),
|
|
4820
4873
|
/** ISO timestamp when the run finished (or createdAt fallback). */
|
|
4821
|
-
date:
|
|
4874
|
+
date: z30.string(),
|
|
4822
4875
|
/**
|
|
4823
4876
|
* 0..100 — same per-query unique-cited definition as
|
|
4824
4877
|
* `ReportExecutiveSummary.citationRate`. Stable across runs with different
|
|
4825
4878
|
* provider counts so the trend line measures real movement rather than
|
|
4826
4879
|
* provider-count variance.
|
|
4827
4880
|
*/
|
|
4828
|
-
citationRate:
|
|
4881
|
+
citationRate: z30.number(),
|
|
4829
4882
|
/** Numerator of `citationRate` for this run. */
|
|
4830
|
-
citedQueryCount:
|
|
4883
|
+
citedQueryCount: z30.number(),
|
|
4831
4884
|
/** Denominator of `citationRate` for this run. */
|
|
4832
|
-
totalQueryCount:
|
|
4885
|
+
totalQueryCount: z30.number(),
|
|
4833
4886
|
/** 0..100 — same per-query unique-mentioned definition as `ReportExecutiveSummary.mentionRate`. */
|
|
4834
|
-
mentionRate:
|
|
4887
|
+
mentionRate: z30.number(),
|
|
4835
4888
|
/** Numerator of `mentionRate` for this run. */
|
|
4836
|
-
mentionedQueryCount:
|
|
4889
|
+
mentionedQueryCount: z30.number(),
|
|
4837
4890
|
/**
|
|
4838
4891
|
* Per-provider rates for the same run. Each provider's rate is per-pair
|
|
4839
4892
|
* within that provider (`cited / scanned`), so it remains comparable
|
|
4840
4893
|
* between providers in the same run.
|
|
4841
4894
|
*/
|
|
4842
|
-
providerRates:
|
|
4843
|
-
provider:
|
|
4844
|
-
citationRate:
|
|
4845
|
-
mentionRate:
|
|
4895
|
+
providerRates: z30.array(z30.object({
|
|
4896
|
+
provider: z30.string(),
|
|
4897
|
+
citationRate: z30.number(),
|
|
4898
|
+
mentionRate: z30.number()
|
|
4846
4899
|
}))
|
|
4847
4900
|
});
|
|
4848
|
-
var reportInsightSchema =
|
|
4849
|
-
id:
|
|
4850
|
-
type:
|
|
4851
|
-
severity:
|
|
4852
|
-
title:
|
|
4853
|
-
query:
|
|
4854
|
-
provider:
|
|
4855
|
-
recommendation:
|
|
4856
|
-
createdAt:
|
|
4901
|
+
var reportInsightSchema = z30.object({
|
|
4902
|
+
id: z30.string(),
|
|
4903
|
+
type: z30.enum(["regression", "gain", "opportunity"]),
|
|
4904
|
+
severity: z30.enum(["critical", "high", "medium", "low"]),
|
|
4905
|
+
title: z30.string(),
|
|
4906
|
+
query: z30.string(),
|
|
4907
|
+
provider: z30.string(),
|
|
4908
|
+
recommendation: z30.string().nullable(),
|
|
4909
|
+
createdAt: z30.string(),
|
|
4857
4910
|
/**
|
|
4858
4911
|
* How many times this insight fired across recent runs for the same
|
|
4859
4912
|
* `(query, provider, type)` tuple. Always ≥ 1. Insights returned by the
|
|
@@ -4861,64 +4914,64 @@ var reportInsightSchema = z29.object({
|
|
|
4861
4914
|
* surfacing the multiplicity. Use it directly instead of grouping again
|
|
4862
4915
|
* client-side — counts derived from raw insight rows will overcount.
|
|
4863
4916
|
*/
|
|
4864
|
-
instanceCount:
|
|
4917
|
+
instanceCount: z30.number()
|
|
4865
4918
|
});
|
|
4866
|
-
var recommendedNextStepSchema =
|
|
4919
|
+
var recommendedNextStepSchema = z30.object({
|
|
4867
4920
|
/** 'immediate' | 'short-term' | 'medium-term' — bucketed by severity heuristic. */
|
|
4868
|
-
horizon:
|
|
4869
|
-
title:
|
|
4870
|
-
rationale:
|
|
4921
|
+
horizon: z30.enum(["immediate", "short-term", "medium-term"]),
|
|
4922
|
+
title: z30.string(),
|
|
4923
|
+
rationale: z30.string()
|
|
4871
4924
|
});
|
|
4872
|
-
var reportRateDeltaSchema =
|
|
4925
|
+
var reportRateDeltaSchema = z30.object({
|
|
4873
4926
|
/** Current value (0..100 for rates, raw count otherwise). When `window`
|
|
4874
4927
|
* is present this is the average over the last `window` checks. */
|
|
4875
|
-
current:
|
|
4928
|
+
current: z30.number(),
|
|
4876
4929
|
/** Prior value compared against. When `window` is present this is the
|
|
4877
4930
|
* average over the prior `window` checks before that. */
|
|
4878
|
-
prior:
|
|
4931
|
+
prior: z30.number(),
|
|
4879
4932
|
/** Absolute delta (current − prior). Negative = decrease. */
|
|
4880
|
-
deltaAbs:
|
|
4933
|
+
deltaAbs: z30.number(),
|
|
4881
4934
|
/**
|
|
4882
4935
|
* Signed percent change vs `prior`, rounded to a whole number. Null when
|
|
4883
4936
|
* `prior <= 0` (percentage undefined). Renderers route count/traffic tiles
|
|
4884
4937
|
* through the "smart %" rule — percentage when the prior base is large
|
|
4885
4938
|
* enough (`MIN_PCT_BASE`), otherwise a rounded raw delta.
|
|
4886
4939
|
*/
|
|
4887
|
-
deltaPct:
|
|
4940
|
+
deltaPct: z30.number().nullable(),
|
|
4888
4941
|
/**
|
|
4889
4942
|
* Direction tag for tone mapping. Threshold is metric-specific (3pp for
|
|
4890
4943
|
* rates, 0.5 for counts) so small noise lands as 'flat' rather than
|
|
4891
4944
|
* flipping up/down each run.
|
|
4892
4945
|
*/
|
|
4893
|
-
direction:
|
|
4946
|
+
direction: z30.enum(["up", "down", "flat"]),
|
|
4894
4947
|
/**
|
|
4895
4948
|
* How many points went into each side of the average. Omitted (or 1)
|
|
4896
4949
|
* means point-to-point (legacy "since last check"). Higher values mean
|
|
4897
4950
|
* a rolling-average comparison — renderers should label it as
|
|
4898
4951
|
* "vs prior N checks" when this is ≥ 2.
|
|
4899
4952
|
*/
|
|
4900
|
-
window:
|
|
4953
|
+
window: z30.number().optional()
|
|
4901
4954
|
});
|
|
4902
|
-
var reportProviderMovementSchema =
|
|
4903
|
-
provider:
|
|
4904
|
-
current:
|
|
4905
|
-
prior:
|
|
4906
|
-
deltaAbs:
|
|
4907
|
-
direction:
|
|
4955
|
+
var reportProviderMovementSchema = z30.object({
|
|
4956
|
+
provider: z30.string(),
|
|
4957
|
+
current: z30.number(),
|
|
4958
|
+
prior: z30.number(),
|
|
4959
|
+
deltaAbs: z30.number(),
|
|
4960
|
+
direction: z30.enum(["up", "down", "flat"])
|
|
4908
4961
|
});
|
|
4909
|
-
var whatsChangedSectionSchema =
|
|
4962
|
+
var whatsChangedSectionSchema = z30.object({
|
|
4910
4963
|
/**
|
|
4911
4964
|
* False when there's no prior run (or fewer than the trend baseline),
|
|
4912
4965
|
* meaning all per-metric deltas will be null. Renderers use this to swap
|
|
4913
4966
|
* in a "establishing baseline" fallback rather than rendering empty
|
|
4914
4967
|
* delta tiles.
|
|
4915
4968
|
*/
|
|
4916
|
-
enoughHistory:
|
|
4969
|
+
enoughHistory: z30.boolean(),
|
|
4917
4970
|
/**
|
|
4918
4971
|
* One-sentence narrative summary suitable as a section subtitle.
|
|
4919
4972
|
* Always present — even on baseline, narrates whatever signal exists.
|
|
4920
4973
|
*/
|
|
4921
|
-
headline:
|
|
4974
|
+
headline: z30.string(),
|
|
4922
4975
|
/** Citation rate delta vs the prior completed run. Null when no prior run. */
|
|
4923
4976
|
citationRate: reportRateDeltaSchema.nullable(),
|
|
4924
4977
|
/** Mention rate delta vs the prior completed run. Null when no prior run. */
|
|
@@ -4946,30 +4999,30 @@ var whatsChangedSectionSchema = z29.object({
|
|
|
4946
4999
|
* deltas "vs prior {comparisonWindowDays} days" off this single value so the
|
|
4947
5000
|
* SPA and HTML stay verbatim-identical.
|
|
4948
5001
|
*/
|
|
4949
|
-
comparisonWindowDays:
|
|
5002
|
+
comparisonWindowDays: z30.number().int().positive(),
|
|
4950
5003
|
/**
|
|
4951
5004
|
* Per-provider citation rate movements (latest run vs prior run). Empty
|
|
4952
5005
|
* when no prior run. Sorted by |deltaAbs| desc — providers with the
|
|
4953
5006
|
* biggest swing first.
|
|
4954
5007
|
*/
|
|
4955
|
-
providerMovements:
|
|
5008
|
+
providerMovements: z30.array(reportProviderMovementSchema),
|
|
4956
5009
|
/**
|
|
4957
5010
|
* Top wins this period — gains surfaced by the intelligence engine.
|
|
4958
5011
|
* Capped at 5; sourced from `insights` filtered to `type: 'gain'`.
|
|
4959
5012
|
*/
|
|
4960
|
-
wins:
|
|
5013
|
+
wins: z30.array(reportInsightSchema),
|
|
4961
5014
|
/**
|
|
4962
5015
|
* Top regressions this period — citations or mentions lost. Capped at 5;
|
|
4963
5016
|
* sourced from `insights` filtered to `type: 'regression'`.
|
|
4964
5017
|
*/
|
|
4965
|
-
regressions:
|
|
4966
|
-
});
|
|
4967
|
-
var reportAudienceSchema =
|
|
4968
|
-
var reportActionAudienceSchema =
|
|
4969
|
-
var reportActionHorizonSchema =
|
|
4970
|
-
var reportActionConfidenceSchema =
|
|
4971
|
-
var reportToneSchema =
|
|
4972
|
-
var reportActionCategorySchema =
|
|
5018
|
+
regressions: z30.array(reportInsightSchema)
|
|
5019
|
+
});
|
|
5020
|
+
var reportAudienceSchema = z30.enum(["agency", "client"]);
|
|
5021
|
+
var reportActionAudienceSchema = z30.enum(["agency", "client", "both"]);
|
|
5022
|
+
var reportActionHorizonSchema = z30.enum(["immediate", "short-term", "medium-term"]);
|
|
5023
|
+
var reportActionConfidenceSchema = z30.enum(["high", "medium", "low"]);
|
|
5024
|
+
var reportToneSchema = z30.enum(["positive", "caution", "negative", "neutral"]);
|
|
5025
|
+
var reportActionCategorySchema = z30.enum([
|
|
4973
5026
|
"content",
|
|
4974
5027
|
"competitors",
|
|
4975
5028
|
"provider",
|
|
@@ -4978,23 +5031,23 @@ var reportActionCategorySchema = z29.enum([
|
|
|
4978
5031
|
"location",
|
|
4979
5032
|
"monitoring"
|
|
4980
5033
|
]);
|
|
4981
|
-
var reportActionPlanItemSchema =
|
|
5034
|
+
var reportActionPlanItemSchema = z30.object({
|
|
4982
5035
|
/** Which report audience should see this action. `both` renders in both modes. */
|
|
4983
5036
|
audience: reportActionAudienceSchema,
|
|
4984
5037
|
/** Stable sort priority. Lower numbers render earlier. */
|
|
4985
|
-
priority:
|
|
5038
|
+
priority: z30.number(),
|
|
4986
5039
|
/** When this should be tackled. */
|
|
4987
5040
|
horizon: reportActionHorizonSchema,
|
|
4988
5041
|
category: reportActionCategorySchema,
|
|
4989
|
-
title:
|
|
5042
|
+
title: z30.string(),
|
|
4990
5043
|
/** Direct next step written as an operator/client-friendly imperative. */
|
|
4991
|
-
action:
|
|
5044
|
+
action: z30.string(),
|
|
4992
5045
|
/** Why this matters. Keep each entry concise and evidence-backed. */
|
|
4993
|
-
why:
|
|
5046
|
+
why: z30.array(z30.string()),
|
|
4994
5047
|
/** Specific observations that justify the action. */
|
|
4995
|
-
evidence:
|
|
5048
|
+
evidence: z30.array(z30.string()),
|
|
4996
5049
|
/** What should move if the action worked. */
|
|
4997
|
-
successMetric:
|
|
5050
|
+
successMetric: z30.string(),
|
|
4998
5051
|
/** Confidence in the recommendation based on the available evidence. */
|
|
4999
5052
|
confidence: reportActionConfidenceSchema,
|
|
5000
5053
|
/**
|
|
@@ -5006,23 +5059,23 @@ var reportActionPlanItemSchema = z29.object({
|
|
|
5006
5059
|
* load. Actions sourced from other signals (competitor gaps, indexing
|
|
5007
5060
|
* issues, etc.) omit this and use their own dismiss flows.
|
|
5008
5061
|
*/
|
|
5009
|
-
targetRef:
|
|
5062
|
+
targetRef: z30.string().optional()
|
|
5010
5063
|
});
|
|
5011
|
-
var reportClientSummarySchema =
|
|
5012
|
-
headline:
|
|
5013
|
-
overview:
|
|
5014
|
-
actionItems:
|
|
5015
|
-
confidenceNotes:
|
|
5064
|
+
var reportClientSummarySchema = z30.object({
|
|
5065
|
+
headline: z30.string(),
|
|
5066
|
+
overview: z30.string(),
|
|
5067
|
+
actionItems: z30.array(reportActionPlanItemSchema),
|
|
5068
|
+
confidenceNotes: z30.array(z30.string())
|
|
5016
5069
|
});
|
|
5017
|
-
var reportAgencyDiagnosticSchema =
|
|
5018
|
-
title:
|
|
5019
|
-
detail:
|
|
5020
|
-
severity:
|
|
5021
|
-
evidence:
|
|
5070
|
+
var reportAgencyDiagnosticSchema = z30.object({
|
|
5071
|
+
title: z30.string(),
|
|
5072
|
+
detail: z30.string(),
|
|
5073
|
+
severity: z30.enum(["positive", "caution", "negative", "neutral"]),
|
|
5074
|
+
evidence: z30.array(z30.string())
|
|
5022
5075
|
});
|
|
5023
|
-
var reportAgencyDiagnosticsSchema =
|
|
5024
|
-
priorities:
|
|
5025
|
-
diagnostics:
|
|
5076
|
+
var reportAgencyDiagnosticsSchema = z30.object({
|
|
5077
|
+
priorities: z30.array(reportActionPlanItemSchema),
|
|
5078
|
+
diagnostics: z30.array(reportAgencyDiagnosticSchema)
|
|
5026
5079
|
});
|
|
5027
5080
|
function reportActionTone(action) {
|
|
5028
5081
|
if (action.horizon === "immediate") return "negative";
|
|
@@ -5080,7 +5133,7 @@ function reportConfidenceLabel(confidence) {
|
|
|
5080
5133
|
return "Low";
|
|
5081
5134
|
}
|
|
5082
5135
|
}
|
|
5083
|
-
var projectReportDtoSchema =
|
|
5136
|
+
var projectReportDtoSchema = z30.object({
|
|
5084
5137
|
meta: reportMetaSchema,
|
|
5085
5138
|
executiveSummary: reportExecutiveSummarySchema,
|
|
5086
5139
|
citationScorecard: citationScorecardSchema,
|
|
@@ -5094,16 +5147,16 @@ var projectReportDtoSchema = z29.object({
|
|
|
5094
5147
|
/** Server-side log-evidence visibility (crawls + click-through sessions). Null when no traffic source connected. */
|
|
5095
5148
|
serverActivity: serverActivitySectionSchema.nullable(),
|
|
5096
5149
|
indexingHealth: indexingHealthSectionSchema.nullable(),
|
|
5097
|
-
citationsTrend:
|
|
5150
|
+
citationsTrend: z30.array(citationsTrendPointSchema),
|
|
5098
5151
|
/**
|
|
5099
5152
|
* Trend-focused "what's changed" summary for the report's act 2. Always
|
|
5100
5153
|
* present; renderers gate empty/baseline states via `enoughHistory`.
|
|
5101
5154
|
*/
|
|
5102
5155
|
whatsChanged: whatsChangedSectionSchema,
|
|
5103
|
-
insights:
|
|
5104
|
-
recommendedNextSteps:
|
|
5156
|
+
insights: z30.array(reportInsightSchema),
|
|
5157
|
+
recommendedNextSteps: z30.array(recommendedNextStepSchema),
|
|
5105
5158
|
/** Canonical structured actions shared by the client and agency render modes. */
|
|
5106
|
-
actionPlan:
|
|
5159
|
+
actionPlan: z30.array(reportActionPlanItemSchema),
|
|
5107
5160
|
/** Polished client-facing summary and action shortlist. */
|
|
5108
5161
|
clientSummary: reportClientSummarySchema,
|
|
5109
5162
|
/** Technical, evidence-oriented operator diagnostics for agency mode. */
|
|
@@ -5113,17 +5166,17 @@ var projectReportDtoSchema = z29.object({
|
|
|
5113
5166
|
* intelligence layer (`buildContentTargetRows`). Empty when no run has
|
|
5114
5167
|
* produced candidate queries with demand or competitor signal.
|
|
5115
5168
|
*/
|
|
5116
|
-
contentOpportunities:
|
|
5169
|
+
contentOpportunities: z30.array(contentTargetRowDtoSchema),
|
|
5117
5170
|
/**
|
|
5118
5171
|
* Queries where competitors were cited but the project was not. Sourced
|
|
5119
5172
|
* from `buildContentGapRows`. Empty until the first answer-visibility run.
|
|
5120
5173
|
*/
|
|
5121
|
-
contentGaps:
|
|
5174
|
+
contentGaps: z30.array(contentGapRowDtoSchema),
|
|
5122
5175
|
/**
|
|
5123
5176
|
* Per-query grounding source map (own + competitor cited URLs). Sourced
|
|
5124
5177
|
* from `buildContentSourceRows`. Empty until the first answer-visibility run.
|
|
5125
5178
|
*/
|
|
5126
|
-
groundingSources:
|
|
5179
|
+
groundingSources: z30.array(contentSourceRowDtoSchema)
|
|
5127
5180
|
});
|
|
5128
5181
|
|
|
5129
5182
|
// ../contracts/src/report-dedup.ts
|
|
@@ -5194,10 +5247,10 @@ function dedupeReportOpportunities(report) {
|
|
|
5194
5247
|
}
|
|
5195
5248
|
|
|
5196
5249
|
// ../contracts/src/skills.ts
|
|
5197
|
-
import { z as
|
|
5198
|
-
var codingAgentSchema =
|
|
5250
|
+
import { z as z31 } from "zod";
|
|
5251
|
+
var codingAgentSchema = z31.enum(["claude", "codex"]);
|
|
5199
5252
|
var CodingAgents = codingAgentSchema.enum;
|
|
5200
|
-
var skillsClientSchema =
|
|
5253
|
+
var skillsClientSchema = z31.enum(["claude", "codex", "all"]);
|
|
5201
5254
|
var SkillsClients = skillsClientSchema.enum;
|
|
5202
5255
|
var SKILL_MANIFEST_FILENAME = ".canonry-skill-manifest.json";
|
|
5203
5256
|
function classifySkillFile(params) {
|
|
@@ -5215,22 +5268,22 @@ function coerceSkillManifest(parsed) {
|
|
|
5215
5268
|
}
|
|
5216
5269
|
|
|
5217
5270
|
// ../contracts/src/traffic.ts
|
|
5218
|
-
import { z as
|
|
5219
|
-
var trafficCrawlerSegmentsSchema =
|
|
5220
|
-
content:
|
|
5221
|
-
sitemap:
|
|
5222
|
-
robots:
|
|
5223
|
-
asset:
|
|
5224
|
-
other:
|
|
5225
|
-
});
|
|
5226
|
-
var trafficPathClassSchema =
|
|
5271
|
+
import { z as z32 } from "zod";
|
|
5272
|
+
var trafficCrawlerSegmentsSchema = z32.object({
|
|
5273
|
+
content: z32.number().int().nonnegative(),
|
|
5274
|
+
sitemap: z32.number().int().nonnegative(),
|
|
5275
|
+
robots: z32.number().int().nonnegative(),
|
|
5276
|
+
asset: z32.number().int().nonnegative(),
|
|
5277
|
+
other: z32.number().int().nonnegative()
|
|
5278
|
+
});
|
|
5279
|
+
var trafficPathClassSchema = z32.enum([
|
|
5227
5280
|
"content",
|
|
5228
5281
|
"sitemap",
|
|
5229
5282
|
"robots",
|
|
5230
5283
|
"asset",
|
|
5231
5284
|
"other"
|
|
5232
5285
|
]);
|
|
5233
|
-
var trafficSourceTypeSchema =
|
|
5286
|
+
var trafficSourceTypeSchema = z32.enum([
|
|
5234
5287
|
"cloud-run",
|
|
5235
5288
|
"wordpress",
|
|
5236
5289
|
"cloudflare",
|
|
@@ -5238,7 +5291,7 @@ var trafficSourceTypeSchema = z31.enum([
|
|
|
5238
5291
|
"generic-log"
|
|
5239
5292
|
]);
|
|
5240
5293
|
var TrafficSourceTypes = trafficSourceTypeSchema.enum;
|
|
5241
|
-
var trafficAdapterCapabilitySchema =
|
|
5294
|
+
var trafficAdapterCapabilitySchema = z32.enum([
|
|
5242
5295
|
"raw-request-events",
|
|
5243
5296
|
"aggregate-request-metrics",
|
|
5244
5297
|
"request-url",
|
|
@@ -5249,252 +5302,252 @@ var trafficAdapterCapabilitySchema = z31.enum([
|
|
|
5249
5302
|
"cursor-pull"
|
|
5250
5303
|
]);
|
|
5251
5304
|
var TrafficAdapterCapabilities = trafficAdapterCapabilitySchema.enum;
|
|
5252
|
-
var trafficEvidenceKindSchema =
|
|
5305
|
+
var trafficEvidenceKindSchema = z32.enum(["raw-request", "aggregate-bucket"]);
|
|
5253
5306
|
var TrafficEvidenceKinds = trafficEvidenceKindSchema.enum;
|
|
5254
|
-
var trafficEventConfidenceSchema =
|
|
5307
|
+
var trafficEventConfidenceSchema = z32.enum(["observed", "provider-aggregated", "inferred"]);
|
|
5255
5308
|
var TrafficEventConfidences = trafficEventConfidenceSchema.enum;
|
|
5256
|
-
var trafficProviderResourceSchema =
|
|
5257
|
-
type:
|
|
5258
|
-
labels:
|
|
5309
|
+
var trafficProviderResourceSchema = z32.object({
|
|
5310
|
+
type: z32.string().nullable(),
|
|
5311
|
+
labels: z32.record(z32.string(), z32.string())
|
|
5259
5312
|
});
|
|
5260
|
-
var normalizedTrafficRequestSchema =
|
|
5313
|
+
var normalizedTrafficRequestSchema = z32.object({
|
|
5261
5314
|
sourceType: trafficSourceTypeSchema,
|
|
5262
|
-
evidenceKind:
|
|
5263
|
-
confidence:
|
|
5264
|
-
eventId:
|
|
5265
|
-
observedAt:
|
|
5266
|
-
method:
|
|
5267
|
-
requestUrl:
|
|
5268
|
-
host:
|
|
5269
|
-
path:
|
|
5270
|
-
queryString:
|
|
5271
|
-
status:
|
|
5272
|
-
userAgent:
|
|
5273
|
-
remoteIp:
|
|
5274
|
-
referer:
|
|
5275
|
-
latencyMs:
|
|
5276
|
-
requestSizeBytes:
|
|
5277
|
-
responseSizeBytes:
|
|
5315
|
+
evidenceKind: z32.literal(TrafficEvidenceKinds["raw-request"]),
|
|
5316
|
+
confidence: z32.literal(TrafficEventConfidences.observed),
|
|
5317
|
+
eventId: z32.string().min(1),
|
|
5318
|
+
observedAt: z32.string().min(1),
|
|
5319
|
+
method: z32.string().nullable(),
|
|
5320
|
+
requestUrl: z32.string().nullable(),
|
|
5321
|
+
host: z32.string().nullable(),
|
|
5322
|
+
path: z32.string().min(1),
|
|
5323
|
+
queryString: z32.string().nullable(),
|
|
5324
|
+
status: z32.number().int().nullable(),
|
|
5325
|
+
userAgent: z32.string().nullable(),
|
|
5326
|
+
remoteIp: z32.string().nullable(),
|
|
5327
|
+
referer: z32.string().nullable(),
|
|
5328
|
+
latencyMs: z32.number().nullable(),
|
|
5329
|
+
requestSizeBytes: z32.number().int().nullable(),
|
|
5330
|
+
responseSizeBytes: z32.number().int().nullable(),
|
|
5278
5331
|
providerResource: trafficProviderResourceSchema,
|
|
5279
|
-
providerLabels:
|
|
5332
|
+
providerLabels: z32.record(z32.string(), z32.string())
|
|
5280
5333
|
});
|
|
5281
|
-
var normalizedTrafficPullPageSchema =
|
|
5282
|
-
events:
|
|
5283
|
-
rawEntryCount:
|
|
5284
|
-
skippedEntryCount:
|
|
5285
|
-
nextPageToken:
|
|
5286
|
-
filter:
|
|
5334
|
+
var normalizedTrafficPullPageSchema = z32.object({
|
|
5335
|
+
events: z32.array(normalizedTrafficRequestSchema),
|
|
5336
|
+
rawEntryCount: z32.number().int().nonnegative(),
|
|
5337
|
+
skippedEntryCount: z32.number().int().nonnegative(),
|
|
5338
|
+
nextPageToken: z32.string().optional(),
|
|
5339
|
+
filter: z32.string()
|
|
5287
5340
|
});
|
|
5288
|
-
var trafficSourceStatusSchema =
|
|
5341
|
+
var trafficSourceStatusSchema = z32.enum(["connected", "paused", "error", "archived"]);
|
|
5289
5342
|
var TrafficSourceStatuses = trafficSourceStatusSchema.enum;
|
|
5290
|
-
var trafficSourceAuthModeSchema =
|
|
5343
|
+
var trafficSourceAuthModeSchema = z32.enum(["oauth", "service-account"]);
|
|
5291
5344
|
var TrafficSourceAuthModes = trafficSourceAuthModeSchema.enum;
|
|
5292
|
-
var verificationStatusSchema =
|
|
5345
|
+
var verificationStatusSchema = z32.enum(["verified", "claimed_unverified", "unknown_ai_like"]);
|
|
5293
5346
|
var VerificationStatuses = verificationStatusSchema.enum;
|
|
5294
|
-
var cloudRunSourceConfigSchema =
|
|
5295
|
-
gcpProjectId:
|
|
5296
|
-
serviceName:
|
|
5297
|
-
location:
|
|
5347
|
+
var cloudRunSourceConfigSchema = z32.object({
|
|
5348
|
+
gcpProjectId: z32.string().min(1),
|
|
5349
|
+
serviceName: z32.string().nullable().optional(),
|
|
5350
|
+
location: z32.string().nullable().optional(),
|
|
5298
5351
|
authMode: trafficSourceAuthModeSchema
|
|
5299
5352
|
});
|
|
5300
|
-
var wordpressTrafficSourceConfigSchema =
|
|
5301
|
-
baseUrl:
|
|
5302
|
-
username:
|
|
5353
|
+
var wordpressTrafficSourceConfigSchema = z32.object({
|
|
5354
|
+
baseUrl: z32.string().url(),
|
|
5355
|
+
username: z32.string().min(1)
|
|
5303
5356
|
});
|
|
5304
|
-
var vercelTrafficEnvironmentSchema =
|
|
5357
|
+
var vercelTrafficEnvironmentSchema = z32.enum(["production", "preview"]);
|
|
5305
5358
|
var VercelTrafficEnvironments = vercelTrafficEnvironmentSchema.enum;
|
|
5306
|
-
var vercelTrafficSourceConfigSchema =
|
|
5359
|
+
var vercelTrafficSourceConfigSchema = z32.object({
|
|
5307
5360
|
/** Vercel project id (e.g. `prj_...`). */
|
|
5308
|
-
projectId:
|
|
5361
|
+
projectId: z32.string().min(1),
|
|
5309
5362
|
/** Vercel team or account id: the org that owns the project. */
|
|
5310
|
-
teamId:
|
|
5363
|
+
teamId: z32.string().min(1),
|
|
5311
5364
|
environment: vercelTrafficEnvironmentSchema
|
|
5312
5365
|
});
|
|
5313
|
-
var trafficSourceDtoSchema =
|
|
5314
|
-
id:
|
|
5315
|
-
projectId:
|
|
5366
|
+
var trafficSourceDtoSchema = z32.object({
|
|
5367
|
+
id: z32.string(),
|
|
5368
|
+
projectId: z32.string(),
|
|
5316
5369
|
sourceType: trafficSourceTypeSchema,
|
|
5317
|
-
displayName:
|
|
5370
|
+
displayName: z32.string(),
|
|
5318
5371
|
status: trafficSourceStatusSchema,
|
|
5319
|
-
lastSyncedAt:
|
|
5320
|
-
lastCursor:
|
|
5321
|
-
lastError:
|
|
5322
|
-
archivedAt:
|
|
5323
|
-
config:
|
|
5324
|
-
createdAt:
|
|
5325
|
-
updatedAt:
|
|
5326
|
-
});
|
|
5327
|
-
var trafficConnectCloudRunRequestSchema =
|
|
5328
|
-
gcpProjectId:
|
|
5329
|
-
serviceName:
|
|
5330
|
-
location:
|
|
5331
|
-
displayName:
|
|
5372
|
+
lastSyncedAt: z32.string().nullable(),
|
|
5373
|
+
lastCursor: z32.string().nullable(),
|
|
5374
|
+
lastError: z32.string().nullable(),
|
|
5375
|
+
archivedAt: z32.string().nullable(),
|
|
5376
|
+
config: z32.record(z32.string(), z32.unknown()),
|
|
5377
|
+
createdAt: z32.string(),
|
|
5378
|
+
updatedAt: z32.string()
|
|
5379
|
+
});
|
|
5380
|
+
var trafficConnectCloudRunRequestSchema = z32.object({
|
|
5381
|
+
gcpProjectId: z32.string().min(1),
|
|
5382
|
+
serviceName: z32.string().min(1).optional(),
|
|
5383
|
+
location: z32.string().min(1).optional(),
|
|
5384
|
+
displayName: z32.string().min(1).optional(),
|
|
5332
5385
|
/** Service-account JSON content (string). When omitted, defaults to OAuth via `canonry google connect <project> --type ga4` flow. */
|
|
5333
|
-
keyJson:
|
|
5386
|
+
keyJson: z32.string().optional()
|
|
5334
5387
|
});
|
|
5335
|
-
var trafficConnectWordpressRequestSchema =
|
|
5336
|
-
baseUrl:
|
|
5337
|
-
username:
|
|
5388
|
+
var trafficConnectWordpressRequestSchema = z32.object({
|
|
5389
|
+
baseUrl: z32.string().url(),
|
|
5390
|
+
username: z32.string().min(1),
|
|
5338
5391
|
/** WordPress Application Password (the same auth used by the content client). */
|
|
5339
|
-
applicationPassword:
|
|
5340
|
-
displayName:
|
|
5392
|
+
applicationPassword: z32.string().min(1),
|
|
5393
|
+
displayName: z32.string().min(1).optional()
|
|
5341
5394
|
});
|
|
5342
|
-
var trafficConnectVercelRequestSchema =
|
|
5395
|
+
var trafficConnectVercelRequestSchema = z32.object({
|
|
5343
5396
|
/** Vercel project id (e.g. `prj_...`) — from the Vercel dashboard or `.vercel/project.json`. */
|
|
5344
|
-
projectId:
|
|
5397
|
+
projectId: z32.string().min(1),
|
|
5345
5398
|
/** Vercel team or account id: the org that owns the project ("orgId" in .vercel/project.json). */
|
|
5346
|
-
teamId:
|
|
5399
|
+
teamId: z32.string().min(1),
|
|
5347
5400
|
/** Vercel personal access token. Stored in `~/.canonry/config.yaml`, never the DB. */
|
|
5348
|
-
token:
|
|
5401
|
+
token: z32.string().min(1),
|
|
5349
5402
|
/** Which deployment environment's request logs to pull. Default: `production`. */
|
|
5350
5403
|
environment: vercelTrafficEnvironmentSchema.optional(),
|
|
5351
|
-
displayName:
|
|
5404
|
+
displayName: z32.string().min(1).optional()
|
|
5352
5405
|
});
|
|
5353
|
-
var trafficSyncResponseSchema =
|
|
5354
|
-
sourceId:
|
|
5355
|
-
runId:
|
|
5356
|
-
syncedAt:
|
|
5357
|
-
pulledEvents:
|
|
5406
|
+
var trafficSyncResponseSchema = z32.object({
|
|
5407
|
+
sourceId: z32.string(),
|
|
5408
|
+
runId: z32.string(),
|
|
5409
|
+
syncedAt: z32.string(),
|
|
5410
|
+
pulledEvents: z32.number().int().nonnegative(),
|
|
5358
5411
|
/** Self-traffic events (Canonry's own tooling) dropped before rollup. */
|
|
5359
|
-
selfTrafficExcluded:
|
|
5360
|
-
crawlerHits:
|
|
5361
|
-
aiUserFetchHits:
|
|
5362
|
-
aiReferralHits:
|
|
5363
|
-
unknownHits:
|
|
5364
|
-
crawlerBucketRows:
|
|
5365
|
-
aiUserFetchBucketRows:
|
|
5366
|
-
aiReferralBucketRows:
|
|
5367
|
-
sampleRows:
|
|
5368
|
-
windowStart:
|
|
5369
|
-
windowEnd:
|
|
5370
|
-
});
|
|
5371
|
-
var trafficBackfillRequestSchema =
|
|
5412
|
+
selfTrafficExcluded: z32.number().int().nonnegative(),
|
|
5413
|
+
crawlerHits: z32.number().int().nonnegative(),
|
|
5414
|
+
aiUserFetchHits: z32.number().int().nonnegative(),
|
|
5415
|
+
aiReferralHits: z32.number().int().nonnegative(),
|
|
5416
|
+
unknownHits: z32.number().int().nonnegative(),
|
|
5417
|
+
crawlerBucketRows: z32.number().int().nonnegative(),
|
|
5418
|
+
aiUserFetchBucketRows: z32.number().int().nonnegative(),
|
|
5419
|
+
aiReferralBucketRows: z32.number().int().nonnegative(),
|
|
5420
|
+
sampleRows: z32.number().int().nonnegative(),
|
|
5421
|
+
windowStart: z32.string(),
|
|
5422
|
+
windowEnd: z32.string()
|
|
5423
|
+
});
|
|
5424
|
+
var trafficBackfillRequestSchema = z32.object({
|
|
5372
5425
|
/** Lookback window in days. Capped server-side at the upstream log retention ceiling (Cloud Logging _Default = 30d). Default: 30. */
|
|
5373
|
-
days:
|
|
5426
|
+
days: z32.number().int().positive().optional()
|
|
5374
5427
|
});
|
|
5375
|
-
var trafficResetRequestSchema =
|
|
5376
|
-
advanceToNow:
|
|
5428
|
+
var trafficResetRequestSchema = z32.object({
|
|
5429
|
+
advanceToNow: z32.literal(true)
|
|
5377
5430
|
});
|
|
5378
|
-
var trafficBackfillResponseSchema =
|
|
5379
|
-
sourceId:
|
|
5380
|
-
runId:
|
|
5431
|
+
var trafficBackfillResponseSchema = z32.object({
|
|
5432
|
+
sourceId: z32.string(),
|
|
5433
|
+
runId: z32.string(),
|
|
5381
5434
|
status: runStatusSchema,
|
|
5382
|
-
windowStart:
|
|
5383
|
-
windowEnd:
|
|
5435
|
+
windowStart: z32.string(),
|
|
5436
|
+
windowEnd: z32.string(),
|
|
5384
5437
|
/** Days actually used after server-side clamping (≤ requested). */
|
|
5385
|
-
daysRequested:
|
|
5386
|
-
daysApplied:
|
|
5438
|
+
daysRequested: z32.number().int().positive(),
|
|
5439
|
+
daysApplied: z32.number().int().positive()
|
|
5387
5440
|
});
|
|
5388
|
-
var trafficSourceTotalsSchema =
|
|
5441
|
+
var trafficSourceTotalsSchema = z32.object({
|
|
5389
5442
|
/**
|
|
5390
5443
|
* Total classified-crawler hits in the window. UNCHANGED contract — still the
|
|
5391
5444
|
* full count across every path class. Use `crawlerContentHits` for the
|
|
5392
5445
|
* "content was actually crawled" signal.
|
|
5393
5446
|
*/
|
|
5394
|
-
crawlerHits:
|
|
5447
|
+
crawlerHits: z32.number().int().nonnegative(),
|
|
5395
5448
|
/** Crawler hits against content/document paths only (= `crawlerSegments.content`). */
|
|
5396
|
-
crawlerContentHits:
|
|
5449
|
+
crawlerContentHits: z32.number().int().nonnegative(),
|
|
5397
5450
|
/** Infrastructure crawler hits — sitemap + robots + asset fetches (`crawlerSegments.{sitemap,robots,asset}`). */
|
|
5398
|
-
crawlerInfraHits:
|
|
5451
|
+
crawlerInfraHits: z32.number().int().nonnegative(),
|
|
5399
5452
|
/** Full per-class crawler-hit breakdown; the five buckets sum to `crawlerHits`. */
|
|
5400
5453
|
crawlerSegments: trafficCrawlerSegmentsSchema,
|
|
5401
|
-
aiUserFetchHits:
|
|
5402
|
-
aiReferralHits:
|
|
5403
|
-
sampleCount:
|
|
5454
|
+
aiUserFetchHits: z32.number().int().nonnegative(),
|
|
5455
|
+
aiReferralHits: z32.number().int().nonnegative(),
|
|
5456
|
+
sampleCount: z32.number().int().nonnegative()
|
|
5404
5457
|
});
|
|
5405
|
-
var trafficSourceListResponseSchema =
|
|
5406
|
-
sources:
|
|
5458
|
+
var trafficSourceListResponseSchema = z32.object({
|
|
5459
|
+
sources: z32.array(trafficSourceDtoSchema)
|
|
5407
5460
|
});
|
|
5408
5461
|
var trafficSourceDetailDtoSchema = trafficSourceDtoSchema.extend({
|
|
5409
5462
|
totals24h: trafficSourceTotalsSchema,
|
|
5410
|
-
latestRun:
|
|
5411
|
-
runId:
|
|
5463
|
+
latestRun: z32.object({
|
|
5464
|
+
runId: z32.string(),
|
|
5412
5465
|
status: runStatusSchema,
|
|
5413
|
-
startedAt:
|
|
5414
|
-
finishedAt:
|
|
5415
|
-
error:
|
|
5466
|
+
startedAt: z32.string().nullable(),
|
|
5467
|
+
finishedAt: z32.string().nullable(),
|
|
5468
|
+
error: z32.string().nullable()
|
|
5416
5469
|
}).nullable()
|
|
5417
5470
|
});
|
|
5418
|
-
var trafficStatusResponseSchema =
|
|
5419
|
-
sources:
|
|
5471
|
+
var trafficStatusResponseSchema = z32.object({
|
|
5472
|
+
sources: z32.array(trafficSourceDetailDtoSchema)
|
|
5420
5473
|
});
|
|
5421
|
-
var trafficEventKindSchema =
|
|
5474
|
+
var trafficEventKindSchema = z32.enum(["crawler", "ai-user-fetch", "ai-referral"]);
|
|
5422
5475
|
var TrafficEventKinds = trafficEventKindSchema.enum;
|
|
5423
|
-
var trafficCrawlerEventEntrySchema =
|
|
5424
|
-
kind:
|
|
5425
|
-
sourceId:
|
|
5426
|
-
tsHour:
|
|
5427
|
-
botId:
|
|
5428
|
-
operator:
|
|
5429
|
-
verificationStatus:
|
|
5430
|
-
pathNormalized:
|
|
5476
|
+
var trafficCrawlerEventEntrySchema = z32.object({
|
|
5477
|
+
kind: z32.literal(TrafficEventKinds.crawler),
|
|
5478
|
+
sourceId: z32.string(),
|
|
5479
|
+
tsHour: z32.string(),
|
|
5480
|
+
botId: z32.string(),
|
|
5481
|
+
operator: z32.string(),
|
|
5482
|
+
verificationStatus: z32.string(),
|
|
5483
|
+
pathNormalized: z32.string(),
|
|
5431
5484
|
/** Coarse class of the fetched path — lets the UI split content crawls from sitemap/robots/asset polling. */
|
|
5432
5485
|
pathClass: trafficPathClassSchema,
|
|
5433
|
-
status:
|
|
5434
|
-
hits:
|
|
5435
|
-
});
|
|
5436
|
-
var trafficAiUserFetchEventEntrySchema =
|
|
5437
|
-
kind:
|
|
5438
|
-
sourceId:
|
|
5439
|
-
tsHour:
|
|
5440
|
-
botId:
|
|
5441
|
-
operator:
|
|
5442
|
-
verificationStatus:
|
|
5443
|
-
pathNormalized:
|
|
5444
|
-
status:
|
|
5445
|
-
hits:
|
|
5446
|
-
});
|
|
5447
|
-
var trafficAiReferralEventEntrySchema =
|
|
5448
|
-
kind:
|
|
5449
|
-
sourceId:
|
|
5450
|
-
tsHour:
|
|
5451
|
-
product:
|
|
5452
|
-
operator:
|
|
5453
|
-
sourceDomain:
|
|
5454
|
-
evidenceType:
|
|
5455
|
-
landingPathNormalized:
|
|
5456
|
-
status:
|
|
5486
|
+
status: z32.number().int(),
|
|
5487
|
+
hits: z32.number().int().nonnegative()
|
|
5488
|
+
});
|
|
5489
|
+
var trafficAiUserFetchEventEntrySchema = z32.object({
|
|
5490
|
+
kind: z32.literal(TrafficEventKinds["ai-user-fetch"]),
|
|
5491
|
+
sourceId: z32.string(),
|
|
5492
|
+
tsHour: z32.string(),
|
|
5493
|
+
botId: z32.string(),
|
|
5494
|
+
operator: z32.string(),
|
|
5495
|
+
verificationStatus: z32.string(),
|
|
5496
|
+
pathNormalized: z32.string(),
|
|
5497
|
+
status: z32.number().int(),
|
|
5498
|
+
hits: z32.number().int().nonnegative()
|
|
5499
|
+
});
|
|
5500
|
+
var trafficAiReferralEventEntrySchema = z32.object({
|
|
5501
|
+
kind: z32.literal(TrafficEventKinds["ai-referral"]),
|
|
5502
|
+
sourceId: z32.string(),
|
|
5503
|
+
tsHour: z32.string(),
|
|
5504
|
+
product: z32.string(),
|
|
5505
|
+
operator: z32.string(),
|
|
5506
|
+
sourceDomain: z32.string(),
|
|
5507
|
+
evidenceType: z32.string(),
|
|
5508
|
+
landingPathNormalized: z32.string(),
|
|
5509
|
+
status: z32.number().int(),
|
|
5457
5510
|
/** Total AI-referral sessions in the bucket. `paidHits + organicHits + unknownHits === hits`. */
|
|
5458
|
-
hits:
|
|
5511
|
+
hits: z32.number().int().nonnegative(),
|
|
5459
5512
|
/** Sessions carrying paid-attribution UTM evidence (`utm_medium=cpc`, …). */
|
|
5460
|
-
paidHits:
|
|
5513
|
+
paidHits: z32.number().int().nonnegative(),
|
|
5461
5514
|
/** Sessions with no paid-attribution evidence. Not proof the click was unpaid — an untagged ad click is indistinguishable. */
|
|
5462
|
-
organicHits:
|
|
5515
|
+
organicHits: z32.number().int().nonnegative(),
|
|
5463
5516
|
/**
|
|
5464
5517
|
* Sessions ingested before the classifier shipped. Their UTM tags were never
|
|
5465
5518
|
* persisted, so they can never be resolved to paid or organic. Never fold
|
|
5466
5519
|
* these into `organicHits`.
|
|
5467
5520
|
*/
|
|
5468
|
-
unknownHits:
|
|
5521
|
+
unknownHits: z32.number().int().nonnegative()
|
|
5469
5522
|
});
|
|
5470
|
-
var trafficEventEntrySchema =
|
|
5523
|
+
var trafficEventEntrySchema = z32.discriminatedUnion("kind", [
|
|
5471
5524
|
trafficCrawlerEventEntrySchema,
|
|
5472
5525
|
trafficAiUserFetchEventEntrySchema,
|
|
5473
5526
|
trafficAiReferralEventEntrySchema
|
|
5474
5527
|
]);
|
|
5475
|
-
var trafficEventsResponseSchema =
|
|
5476
|
-
windowStart:
|
|
5477
|
-
windowEnd:
|
|
5478
|
-
totals:
|
|
5528
|
+
var trafficEventsResponseSchema = z32.object({
|
|
5529
|
+
windowStart: z32.string(),
|
|
5530
|
+
windowEnd: z32.string(),
|
|
5531
|
+
totals: z32.object({
|
|
5479
5532
|
/** Total classified-crawler hits across the window. UNCHANGED contract. */
|
|
5480
|
-
crawlerHits:
|
|
5533
|
+
crawlerHits: z32.number().int().nonnegative(),
|
|
5481
5534
|
/** Crawler hits against content/document paths only (= `crawlerSegments.content`). */
|
|
5482
|
-
crawlerContentHits:
|
|
5535
|
+
crawlerContentHits: z32.number().int().nonnegative(),
|
|
5483
5536
|
/** Infrastructure crawler hits — sitemap + robots + asset fetches. */
|
|
5484
|
-
crawlerInfraHits:
|
|
5537
|
+
crawlerInfraHits: z32.number().int().nonnegative(),
|
|
5485
5538
|
/** Full per-class crawler-hit breakdown; the five buckets sum to `crawlerHits`. */
|
|
5486
5539
|
crawlerSegments: trafficCrawlerSegmentsSchema,
|
|
5487
|
-
aiUserFetchHits:
|
|
5540
|
+
aiUserFetchHits: z32.number().int().nonnegative(),
|
|
5488
5541
|
/** Total AI-referral sessions. The three class buckets below sum to it. */
|
|
5489
|
-
aiReferralHits:
|
|
5542
|
+
aiReferralHits: z32.number().int().nonnegative(),
|
|
5490
5543
|
/** AI-referral sessions carrying paid-attribution UTM evidence. */
|
|
5491
|
-
aiReferralPaidHits:
|
|
5544
|
+
aiReferralPaidHits: z32.number().int().nonnegative(),
|
|
5492
5545
|
/** AI-referral sessions with no paid-attribution evidence. */
|
|
5493
|
-
aiReferralOrganicHits:
|
|
5546
|
+
aiReferralOrganicHits: z32.number().int().nonnegative(),
|
|
5494
5547
|
/** AI-referral sessions ingested before the classifier shipped; unresolvable, never organic. */
|
|
5495
|
-
aiReferralUnknownHits:
|
|
5548
|
+
aiReferralUnknownHits: z32.number().int().nonnegative()
|
|
5496
5549
|
}),
|
|
5497
|
-
events:
|
|
5550
|
+
events: z32.array(trafficEventEntrySchema)
|
|
5498
5551
|
});
|
|
5499
5552
|
|
|
5500
5553
|
// ../contracts/src/traffic-path.ts
|
|
@@ -5637,14 +5690,14 @@ function round(value, dp = 4) {
|
|
|
5637
5690
|
const f = 10 ** dp;
|
|
5638
5691
|
return (Math.round(value * f) + 0) / f;
|
|
5639
5692
|
}
|
|
5640
|
-
function wilsonInterval(successes, n,
|
|
5693
|
+
function wilsonInterval(successes, n, z34 = 1.96) {
|
|
5641
5694
|
if (!Number.isFinite(n) || n <= 0) return null;
|
|
5642
5695
|
const s = Math.max(0, Math.min(successes, n));
|
|
5643
5696
|
const p = s / n;
|
|
5644
|
-
const z210 =
|
|
5697
|
+
const z210 = z34 * z34;
|
|
5645
5698
|
const denom = 1 + z210 / n;
|
|
5646
5699
|
const center = (p + z210 / (2 * n)) / denom;
|
|
5647
|
-
const margin =
|
|
5700
|
+
const margin = z34 / denom * Math.sqrt(p * (1 - p) / n + z210 / (4 * n * n));
|
|
5648
5701
|
return {
|
|
5649
5702
|
low: round(Math.max(0, center - margin)),
|
|
5650
5703
|
high: round(Math.min(1, center + margin))
|
|
@@ -5652,114 +5705,114 @@ function wilsonInterval(successes, n, z33 = 1.96) {
|
|
|
5652
5705
|
}
|
|
5653
5706
|
|
|
5654
5707
|
// ../contracts/src/ads.ts
|
|
5655
|
-
import { z as
|
|
5656
|
-
var adsConnectRequestSchema =
|
|
5708
|
+
import { z as z33 } from "zod";
|
|
5709
|
+
var adsConnectRequestSchema = z33.object({
|
|
5657
5710
|
/** Ads Manager "SDK key" scoped to one ad account. Stored in config.yaml, never the DB. */
|
|
5658
|
-
apiKey:
|
|
5659
|
-
});
|
|
5660
|
-
var adsConnectionStatusDtoSchema =
|
|
5661
|
-
connected:
|
|
5662
|
-
adAccountId:
|
|
5663
|
-
displayName:
|
|
5664
|
-
currencyCode:
|
|
5665
|
-
timezone:
|
|
5666
|
-
status:
|
|
5667
|
-
lastSyncedAt:
|
|
5711
|
+
apiKey: z33.string().min(1)
|
|
5712
|
+
});
|
|
5713
|
+
var adsConnectionStatusDtoSchema = z33.object({
|
|
5714
|
+
connected: z33.boolean(),
|
|
5715
|
+
adAccountId: z33.string().nullable().optional(),
|
|
5716
|
+
displayName: z33.string().nullable().optional(),
|
|
5717
|
+
currencyCode: z33.string().nullable().optional(),
|
|
5718
|
+
timezone: z33.string().nullable().optional(),
|
|
5719
|
+
status: z33.string().nullable().optional(),
|
|
5720
|
+
lastSyncedAt: z33.string().nullable().optional(),
|
|
5668
5721
|
/** Whether the ad account has OpenAI conversion tracking (pixel or CAPI) configured,
|
|
5669
5722
|
* detected from synced campaigns carrying conversion_event_setting_ids. Optional:
|
|
5670
5723
|
* only present when connected. */
|
|
5671
|
-
conversionTrackingConfigured:
|
|
5672
|
-
});
|
|
5673
|
-
var adsDisconnectResponseSchema =
|
|
5674
|
-
disconnected:
|
|
5675
|
-
});
|
|
5676
|
-
var adsSyncResponseSchema =
|
|
5677
|
-
runId:
|
|
5678
|
-
status:
|
|
5679
|
-
});
|
|
5680
|
-
var adsCreativeDtoSchema =
|
|
5681
|
-
type:
|
|
5682
|
-
title:
|
|
5683
|
-
body:
|
|
5684
|
-
targetUrl:
|
|
5685
|
-
});
|
|
5686
|
-
var adsAdDtoSchema =
|
|
5687
|
-
id:
|
|
5688
|
-
adGroupId:
|
|
5689
|
-
name:
|
|
5690
|
-
status:
|
|
5691
|
-
reviewStatus:
|
|
5724
|
+
conversionTrackingConfigured: z33.boolean().optional()
|
|
5725
|
+
});
|
|
5726
|
+
var adsDisconnectResponseSchema = z33.object({
|
|
5727
|
+
disconnected: z33.boolean()
|
|
5728
|
+
});
|
|
5729
|
+
var adsSyncResponseSchema = z33.object({
|
|
5730
|
+
runId: z33.string(),
|
|
5731
|
+
status: z33.string()
|
|
5732
|
+
});
|
|
5733
|
+
var adsCreativeDtoSchema = z33.object({
|
|
5734
|
+
type: z33.string().nullable().optional(),
|
|
5735
|
+
title: z33.string().nullable().optional(),
|
|
5736
|
+
body: z33.string().nullable().optional(),
|
|
5737
|
+
targetUrl: z33.string().nullable().optional()
|
|
5738
|
+
});
|
|
5739
|
+
var adsAdDtoSchema = z33.object({
|
|
5740
|
+
id: z33.string(),
|
|
5741
|
+
adGroupId: z33.string(),
|
|
5742
|
+
name: z33.string(),
|
|
5743
|
+
status: z33.string(),
|
|
5744
|
+
reviewStatus: z33.string().nullable().optional(),
|
|
5692
5745
|
creative: adsCreativeDtoSchema.nullable().optional()
|
|
5693
5746
|
});
|
|
5694
|
-
var adsAdGroupDtoSchema =
|
|
5695
|
-
id:
|
|
5696
|
-
campaignId:
|
|
5697
|
-
name:
|
|
5698
|
-
status:
|
|
5699
|
-
billingEventType:
|
|
5700
|
-
maxBidMicros:
|
|
5747
|
+
var adsAdGroupDtoSchema = z33.object({
|
|
5748
|
+
id: z33.string(),
|
|
5749
|
+
campaignId: z33.string(),
|
|
5750
|
+
name: z33.string(),
|
|
5751
|
+
status: z33.string(),
|
|
5752
|
+
billingEventType: z33.string().nullable().optional(),
|
|
5753
|
+
maxBidMicros: z33.number().int().nullable().optional(),
|
|
5701
5754
|
/**
|
|
5702
5755
|
* The targeting primitive: entries are multi-line strings of
|
|
5703
5756
|
* newline-separated example queries (the live Ads Manager format).
|
|
5704
5757
|
*/
|
|
5705
|
-
contextHints:
|
|
5706
|
-
ads:
|
|
5707
|
-
});
|
|
5708
|
-
var adsCampaignDtoSchema =
|
|
5709
|
-
id:
|
|
5710
|
-
name:
|
|
5711
|
-
status:
|
|
5712
|
-
biddingType:
|
|
5713
|
-
dailySpendLimitMicros:
|
|
5714
|
-
lifetimeSpendLimitMicros:
|
|
5715
|
-
adGroups:
|
|
5716
|
-
});
|
|
5717
|
-
var adsCampaignListResponseSchema =
|
|
5718
|
-
campaigns:
|
|
5719
|
-
});
|
|
5720
|
-
var adsInsightLevelSchema =
|
|
5758
|
+
contextHints: z33.array(z33.string()).default([]),
|
|
5759
|
+
ads: z33.array(adsAdDtoSchema).default([])
|
|
5760
|
+
});
|
|
5761
|
+
var adsCampaignDtoSchema = z33.object({
|
|
5762
|
+
id: z33.string(),
|
|
5763
|
+
name: z33.string(),
|
|
5764
|
+
status: z33.string(),
|
|
5765
|
+
biddingType: z33.string().nullable().optional(),
|
|
5766
|
+
dailySpendLimitMicros: z33.number().int().nullable().optional(),
|
|
5767
|
+
lifetimeSpendLimitMicros: z33.number().int().nullable().optional(),
|
|
5768
|
+
adGroups: z33.array(adsAdGroupDtoSchema).default([])
|
|
5769
|
+
});
|
|
5770
|
+
var adsCampaignListResponseSchema = z33.object({
|
|
5771
|
+
campaigns: z33.array(adsCampaignDtoSchema)
|
|
5772
|
+
});
|
|
5773
|
+
var adsInsightLevelSchema = z33.enum(["campaign", "ad_group"]);
|
|
5721
5774
|
var AdsInsightLevels = adsInsightLevelSchema.enum;
|
|
5722
|
-
var adsInsightRowDtoSchema =
|
|
5775
|
+
var adsInsightRowDtoSchema = z33.object({
|
|
5723
5776
|
level: adsInsightLevelSchema,
|
|
5724
|
-
entityId:
|
|
5725
|
-
date:
|
|
5726
|
-
impressions:
|
|
5727
|
-
clicks:
|
|
5728
|
-
spendMicros:
|
|
5777
|
+
entityId: z33.string(),
|
|
5778
|
+
date: z33.string(),
|
|
5779
|
+
impressions: z33.number().int(),
|
|
5780
|
+
clicks: z33.number().int(),
|
|
5781
|
+
spendMicros: z33.number().int(),
|
|
5729
5782
|
/** Conversion count for the row. 0 when conversion tracking is not configured.
|
|
5730
5783
|
* Conversion VALUE (for ROAS) is a deliberate follow-up: the upstream value
|
|
5731
5784
|
* field is not yet captured against a live conversion-tracking account. */
|
|
5732
|
-
conversions:
|
|
5785
|
+
conversions: z33.number().int(),
|
|
5733
5786
|
/** clicks / impressions; null when impressions is 0. */
|
|
5734
|
-
ctr:
|
|
5787
|
+
ctr: z33.number().nullable(),
|
|
5735
5788
|
/** spendMicros / clicks, rounded to integer micros; null when clicks is 0. */
|
|
5736
|
-
cpcMicros:
|
|
5789
|
+
cpcMicros: z33.number().int().nullable()
|
|
5737
5790
|
});
|
|
5738
|
-
var adsInsightsResponseSchema =
|
|
5739
|
-
rows:
|
|
5791
|
+
var adsInsightsResponseSchema = z33.object({
|
|
5792
|
+
rows: z33.array(adsInsightRowDtoSchema),
|
|
5740
5793
|
/** Account currency for rendering spend/cpc; null before the first sync. */
|
|
5741
|
-
currencyCode:
|
|
5742
|
-
});
|
|
5743
|
-
var adsTotalsDtoSchema =
|
|
5744
|
-
impressions:
|
|
5745
|
-
clicks:
|
|
5746
|
-
spendMicros:
|
|
5747
|
-
conversions:
|
|
5748
|
-
ctr:
|
|
5749
|
-
cpcMicros:
|
|
5750
|
-
});
|
|
5751
|
-
var adsSummaryDtoSchema =
|
|
5752
|
-
connected:
|
|
5753
|
-
displayName:
|
|
5754
|
-
currencyCode:
|
|
5755
|
-
lastSyncedAt:
|
|
5756
|
-
campaignCount:
|
|
5757
|
-
adGroupCount:
|
|
5758
|
-
adCount:
|
|
5794
|
+
currencyCode: z33.string().nullable().optional()
|
|
5795
|
+
});
|
|
5796
|
+
var adsTotalsDtoSchema = z33.object({
|
|
5797
|
+
impressions: z33.number().int(),
|
|
5798
|
+
clicks: z33.number().int(),
|
|
5799
|
+
spendMicros: z33.number().int(),
|
|
5800
|
+
conversions: z33.number().int(),
|
|
5801
|
+
ctr: z33.number().nullable(),
|
|
5802
|
+
cpcMicros: z33.number().int().nullable()
|
|
5803
|
+
});
|
|
5804
|
+
var adsSummaryDtoSchema = z33.object({
|
|
5805
|
+
connected: z33.boolean(),
|
|
5806
|
+
displayName: z33.string().nullable().optional(),
|
|
5807
|
+
currencyCode: z33.string().nullable().optional(),
|
|
5808
|
+
lastSyncedAt: z33.string().nullable().optional(),
|
|
5809
|
+
campaignCount: z33.number().int(),
|
|
5810
|
+
adGroupCount: z33.number().int(),
|
|
5811
|
+
adCount: z33.number().int(),
|
|
5759
5812
|
/** Date range the totals cover (oldest/newest rollup date), null when empty. */
|
|
5760
|
-
window:
|
|
5761
|
-
from:
|
|
5762
|
-
to:
|
|
5813
|
+
window: z33.object({
|
|
5814
|
+
from: z33.string().nullable(),
|
|
5815
|
+
to: z33.string().nullable()
|
|
5763
5816
|
}),
|
|
5764
5817
|
/** Campaign-level rollup totals over the window (levels are not summed across). */
|
|
5765
5818
|
totals: adsTotalsDtoSchema
|
|
@@ -6059,8 +6112,10 @@ export {
|
|
|
6059
6112
|
LlmCapabilities,
|
|
6060
6113
|
LLM_CAPABILITIES,
|
|
6061
6114
|
settingsDtoSchema,
|
|
6115
|
+
runStatusSchema,
|
|
6062
6116
|
RunStatuses,
|
|
6063
6117
|
RunKinds,
|
|
6118
|
+
runTriggerSchema,
|
|
6064
6119
|
RunTriggers,
|
|
6065
6120
|
citationStateSchema,
|
|
6066
6121
|
CitationStates,
|
|
@@ -6136,6 +6191,7 @@ export {
|
|
|
6136
6191
|
visibilityStatsDtoSchema,
|
|
6137
6192
|
visibilityCompareDtoSchema,
|
|
6138
6193
|
calendarMonthBounds,
|
|
6194
|
+
resultsExportDtoSchema,
|
|
6139
6195
|
formatRatio,
|
|
6140
6196
|
formatNumber,
|
|
6141
6197
|
formatDate,
|