@ainyc/canonry 4.83.0 → 4.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/aero/SKILL.md +14 -10
- package/assets/agent-workspace/skills/aero/references/aeo-discovery.md +7 -5
- package/assets/agent-workspace/skills/aero/references/memory-patterns.md +1 -1
- package/assets/agent-workspace/skills/aero/references/orchestration.md +22 -20
- package/assets/agent-workspace/skills/aero/references/regression-playbook.md +11 -9
- package/assets/agent-workspace/skills/aero/references/reporting.md +14 -9
- package/assets/agent-workspace/skills/aero/soul.md +5 -5
- package/assets/agent-workspace/skills/canonry/SKILL.md +1 -1
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +84 -36
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +44 -10
- package/assets/assets/{BacklinksPage-OrSg_iPA.js → BacklinksPage-CDAv0ggn.js} +1 -1
- package/assets/assets/{ChartPrimitives-DPBhAT_r.js → ChartPrimitives-CnAmsyt7.js} +1 -1
- package/assets/assets/{ProjectPage-CpMcEmtw.js → ProjectPage-C9KEgRxD.js} +1 -1
- package/assets/assets/{RunRow-2Rty0BAH.js → RunRow-CVZ5o8fg.js} +1 -1
- package/assets/assets/{RunsPage-B3ahqf8s.js → RunsPage-Bzy5c0MZ.js} +1 -1
- package/assets/assets/{SettingsPage-BIjeI85q.js → SettingsPage-B1ocxPBe.js} +1 -1
- package/assets/assets/{TrafficPage-DjGoj691.js → TrafficPage-D2zepQOC.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BgKG-2q3.js → TrafficSourceDetailPage-C7JuAkaK.js} +1 -1
- package/assets/assets/{arrow-left-Cf7wmru1.js → arrow-left-Bv3CWylm.js} +1 -1
- package/assets/assets/{extract-error-message-CANxezte.js → extract-error-message-BtVid5TP.js} +1 -1
- package/assets/assets/{index-CGlPx_cu.js → index-DmNti_xn.js} +72 -72
- package/assets/assets/{trash-2-6nHJZrvy.js → trash-2-BoimCsYz.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-GOWH42QV.js → chunk-3K3QRSYE.js} +709 -426
- package/dist/{chunk-Y3O3HBMN.js → chunk-62YB3ML7.js} +49 -1
- package/dist/{chunk-NRACXNI7.js → chunk-7BMSWI2K.js} +6 -4
- package/dist/{chunk-BNF3HXBW.js → chunk-I2BJC3DT.js} +1021 -942
- package/dist/cli.js +165 -29
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-FHQM7YMA.js → intelligence-service-AHHBQKRD.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +7 -7
|
@@ -2142,30 +2142,101 @@ function windowCutoff(window) {
|
|
|
2142
2142
|
return d.toISOString();
|
|
2143
2143
|
}
|
|
2144
2144
|
|
|
2145
|
-
// ../contracts/src/
|
|
2145
|
+
// ../contracts/src/visibility-stats.ts
|
|
2146
2146
|
import { z as z20 } from "zod";
|
|
2147
|
-
var
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
var
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2147
|
+
var visibilityStatsCountsSchema = z20.object({
|
|
2148
|
+
/** Total (query × provider) snapshots observed in the window. Denominator for `citedRate`. */
|
|
2149
|
+
total: z20.number().int(),
|
|
2150
|
+
/**
|
|
2151
|
+
* Snapshots where `answerMentioned !== null` — the sample size (`n`) for the
|
|
2152
|
+
* mention proportion. Tri-state `null` ("not checked") is excluded.
|
|
2153
|
+
*/
|
|
2154
|
+
checked: z20.number().int(),
|
|
2155
|
+
/** Snapshots where `answerMentioned === true` (brand named in the answer text). */
|
|
2156
|
+
mentioned: z20.number().int(),
|
|
2157
|
+
/** Snapshots where `citationState === 'cited'` (domain in the grounding / source list). */
|
|
2158
|
+
cited: z20.number().int(),
|
|
2159
|
+
/** `mentioned / checked`, rounded to 4 dp; `null` when `checked === 0` (rate undefined over no samples). */
|
|
2160
|
+
mentionRate: z20.number().nullable(),
|
|
2161
|
+
/** `cited / total`, rounded to 4 dp; `null` when `total === 0`. */
|
|
2162
|
+
citedRate: z20.number().nullable()
|
|
2163
|
+
});
|
|
2164
|
+
var visibilityStatsProviderEntrySchema = visibilityStatsCountsSchema.extend({
|
|
2165
|
+
provider: z20.string(),
|
|
2166
|
+
/** Earliest snapshot `createdAt` (ISO 8601) contributing to these counts. */
|
|
2167
|
+
firstObserved: z20.string(),
|
|
2168
|
+
/** Latest snapshot `createdAt` (ISO 8601) contributing to these counts. */
|
|
2169
|
+
lastObserved: z20.string()
|
|
2170
|
+
});
|
|
2171
|
+
var visibilityStatsQueryEntrySchema = visibilityStatsCountsSchema.extend({
|
|
2172
|
+
/** The tracked query's id. */
|
|
2173
|
+
queryId: z20.string().nullable(),
|
|
2174
|
+
/** The query text. */
|
|
2175
|
+
query: z20.string(),
|
|
2176
|
+
firstObserved: z20.string(),
|
|
2177
|
+
lastObserved: z20.string(),
|
|
2178
|
+
/**
|
|
2179
|
+
* Per-provider breakdown — present only when `groupBy=provider`. Each
|
|
2180
|
+
* entry's counts sum to this query's pooled counts.
|
|
2181
|
+
*/
|
|
2182
|
+
providers: z20.array(visibilityStatsProviderEntrySchema).optional()
|
|
2183
|
+
});
|
|
2184
|
+
var visibilityStatsWindowSchema = z20.object({
|
|
2185
|
+
/** Inclusive lower bound on `runs.createdAt` (ISO 8601; a date-only value is that UTC day's start), or `null` for unbounded. Echoes the raw value the caller passed. */
|
|
2186
|
+
since: z20.string().nullable(),
|
|
2187
|
+
/** Inclusive upper bound on `runs.createdAt` (ISO 8601; a date-only value covers the whole UTC day), or `null` for unbounded. Echoes the raw value the caller passed. */
|
|
2188
|
+
until: z20.string().nullable(),
|
|
2189
|
+
/** When set, the aggregation used the most recent N answer-visibility runs instead of a date window. */
|
|
2190
|
+
lastRuns: z20.number().int().nullable(),
|
|
2191
|
+
/** Number of (completed / partial, non-probe) answer-visibility runs included. */
|
|
2192
|
+
runCount: z20.number().int()
|
|
2193
|
+
});
|
|
2194
|
+
var visibilityStatsGroupBySchema = z20.enum(["provider"]);
|
|
2195
|
+
var visibilityStatsDtoSchema = z20.object({
|
|
2196
|
+
project: z20.string(),
|
|
2197
|
+
/**
|
|
2198
|
+
* `'provider'` when a per-provider breakdown was requested; OMITTED otherwise
|
|
2199
|
+
* (absent = no breakdown). Optional rather than nullable so the generated SDK
|
|
2200
|
+
* types it `groupBy?: 'provider'` — hey-api drops `null` on a single-value
|
|
2201
|
+
* nullable enum, which would mistype the no-breakdown (common) case.
|
|
2202
|
+
*/
|
|
2203
|
+
groupBy: visibilityStatsGroupBySchema.optional(),
|
|
2204
|
+
window: visibilityStatsWindowSchema,
|
|
2205
|
+
/** Pooled counts across every tracked query in the window. */
|
|
2206
|
+
totals: visibilityStatsCountsSchema,
|
|
2207
|
+
/**
|
|
2208
|
+
* Pooled per-provider counts across every tracked query — present only when
|
|
2209
|
+
* `groupBy=provider`. Each entry's counts sum to `totals`.
|
|
2210
|
+
*/
|
|
2211
|
+
byProvider: z20.array(visibilityStatsProviderEntrySchema).optional(),
|
|
2212
|
+
/** Per-query stats, sorted by query text. Only queries with ≥1 snapshot in the window appear. */
|
|
2213
|
+
queries: z20.array(visibilityStatsQueryEntrySchema)
|
|
2214
|
+
});
|
|
2215
|
+
|
|
2216
|
+
// ../contracts/src/ga.ts
|
|
2217
|
+
import { z as z21 } from "zod";
|
|
2218
|
+
var ga4ConnectionDtoSchema = z21.object({
|
|
2219
|
+
id: z21.string(),
|
|
2220
|
+
projectId: z21.string(),
|
|
2221
|
+
propertyId: z21.string(),
|
|
2222
|
+
clientEmail: z21.string(),
|
|
2223
|
+
connected: z21.boolean(),
|
|
2224
|
+
createdAt: z21.string(),
|
|
2225
|
+
updatedAt: z21.string()
|
|
2226
|
+
});
|
|
2227
|
+
var ga4TrafficSnapshotDtoSchema = z21.object({
|
|
2228
|
+
date: z21.string(),
|
|
2229
|
+
landingPage: z21.string(),
|
|
2230
|
+
sessions: z21.number(),
|
|
2231
|
+
organicSessions: z21.number(),
|
|
2232
|
+
users: z21.number()
|
|
2233
|
+
});
|
|
2234
|
+
var ga4SourceDimensionSchema = z21.enum(["session", "first_user", "manual_utm"]);
|
|
2235
|
+
var ga4AiReferralDtoSchema = z21.object({
|
|
2236
|
+
source: z21.string(),
|
|
2237
|
+
medium: z21.string(),
|
|
2238
|
+
sessions: z21.number(),
|
|
2239
|
+
users: z21.number(),
|
|
2169
2240
|
/**
|
|
2170
2241
|
* The winning attribution dimension for this (source, medium) tuple — the
|
|
2171
2242
|
* one with the highest session count. GA4 emits one row per dimension
|
|
@@ -2175,144 +2246,144 @@ var ga4AiReferralDtoSchema = z20.object({
|
|
|
2175
2246
|
*/
|
|
2176
2247
|
sourceDimension: ga4SourceDimensionSchema
|
|
2177
2248
|
});
|
|
2178
|
-
var ga4AiReferralLandingPageDtoSchema =
|
|
2179
|
-
source:
|
|
2180
|
-
medium:
|
|
2249
|
+
var ga4AiReferralLandingPageDtoSchema = z21.object({
|
|
2250
|
+
source: z21.string(),
|
|
2251
|
+
medium: z21.string(),
|
|
2181
2252
|
/**
|
|
2182
2253
|
* The winning attribution dimension for this (source, medium, landingPage)
|
|
2183
2254
|
* tuple — the one with the highest session count.
|
|
2184
2255
|
*/
|
|
2185
2256
|
sourceDimension: ga4SourceDimensionSchema,
|
|
2186
|
-
landingPage:
|
|
2187
|
-
sessions:
|
|
2188
|
-
users:
|
|
2189
|
-
});
|
|
2190
|
-
var ga4SocialReferralDtoSchema =
|
|
2191
|
-
source:
|
|
2192
|
-
medium:
|
|
2193
|
-
sessions:
|
|
2194
|
-
users:
|
|
2257
|
+
landingPage: z21.string(),
|
|
2258
|
+
sessions: z21.number(),
|
|
2259
|
+
users: z21.number()
|
|
2260
|
+
});
|
|
2261
|
+
var ga4SocialReferralDtoSchema = z21.object({
|
|
2262
|
+
source: z21.string(),
|
|
2263
|
+
medium: z21.string(),
|
|
2264
|
+
sessions: z21.number(),
|
|
2265
|
+
users: z21.number(),
|
|
2195
2266
|
/** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
|
|
2196
|
-
channelGroup:
|
|
2267
|
+
channelGroup: z21.string()
|
|
2197
2268
|
});
|
|
2198
|
-
var ga4ChannelBucketDtoSchema =
|
|
2199
|
-
sessions:
|
|
2200
|
-
sharePct:
|
|
2201
|
-
sharePctDisplay:
|
|
2269
|
+
var ga4ChannelBucketDtoSchema = z21.object({
|
|
2270
|
+
sessions: z21.number(),
|
|
2271
|
+
sharePct: z21.number(),
|
|
2272
|
+
sharePctDisplay: z21.string()
|
|
2202
2273
|
});
|
|
2203
|
-
var ga4ChannelBreakdownDtoSchema =
|
|
2274
|
+
var ga4ChannelBreakdownDtoSchema = z21.object({
|
|
2204
2275
|
organic: ga4ChannelBucketDtoSchema,
|
|
2205
2276
|
social: ga4ChannelBucketDtoSchema,
|
|
2206
2277
|
direct: ga4ChannelBucketDtoSchema,
|
|
2207
2278
|
ai: ga4ChannelBucketDtoSchema,
|
|
2208
2279
|
other: ga4ChannelBucketDtoSchema
|
|
2209
2280
|
});
|
|
2210
|
-
var ga4TrafficSummaryDtoSchema =
|
|
2211
|
-
totalSessions:
|
|
2212
|
-
totalOrganicSessions:
|
|
2281
|
+
var ga4TrafficSummaryDtoSchema = z21.object({
|
|
2282
|
+
totalSessions: z21.number(),
|
|
2283
|
+
totalOrganicSessions: z21.number(),
|
|
2213
2284
|
/** 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. */
|
|
2214
|
-
totalDirectSessions:
|
|
2215
|
-
totalUsers:
|
|
2216
|
-
topPages:
|
|
2217
|
-
landingPage:
|
|
2218
|
-
sessions:
|
|
2219
|
-
organicSessions:
|
|
2285
|
+
totalDirectSessions: z21.number(),
|
|
2286
|
+
totalUsers: z21.number(),
|
|
2287
|
+
topPages: z21.array(z21.object({
|
|
2288
|
+
landingPage: z21.string(),
|
|
2289
|
+
sessions: z21.number(),
|
|
2290
|
+
organicSessions: z21.number(),
|
|
2220
2291
|
/** Per-page Direct-channel sessions. 0 for legacy rows. */
|
|
2221
|
-
directSessions:
|
|
2222
|
-
users:
|
|
2292
|
+
directSessions: z21.number(),
|
|
2293
|
+
users: z21.number()
|
|
2223
2294
|
})),
|
|
2224
|
-
aiReferrals:
|
|
2225
|
-
aiReferralLandingPages:
|
|
2295
|
+
aiReferrals: z21.array(ga4AiReferralDtoSchema),
|
|
2296
|
+
aiReferralLandingPages: z21.array(ga4AiReferralLandingPageDtoSchema),
|
|
2226
2297
|
/** 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. */
|
|
2227
|
-
aiSessionsDeduped:
|
|
2298
|
+
aiSessionsDeduped: z21.number(),
|
|
2228
2299
|
/** Deduped AI user total: MAX(users) per date+source+medium across attribution dimensions, then summed. */
|
|
2229
|
-
aiUsersDeduped:
|
|
2300
|
+
aiUsersDeduped: z21.number(),
|
|
2230
2301
|
/** AI sessions whose CURRENT sessionSource matched an AI engine. Can overlap with raw Organic/Social/Direct totals; `channelBreakdown` removes those overlaps for display. */
|
|
2231
|
-
aiSessionsBySession:
|
|
2302
|
+
aiSessionsBySession: z21.number(),
|
|
2232
2303
|
/** AI users whose CURRENT sessionSource matched an AI engine. Can overlap with raw Organic/Social/Direct totals. */
|
|
2233
|
-
aiUsersBySession:
|
|
2234
|
-
socialReferrals:
|
|
2304
|
+
aiUsersBySession: z21.number(),
|
|
2305
|
+
socialReferrals: z21.array(ga4SocialReferralDtoSchema),
|
|
2235
2306
|
/** Total social sessions (session-scoped, no cross-dimension dedup needed). */
|
|
2236
|
-
socialSessions:
|
|
2307
|
+
socialSessions: z21.number(),
|
|
2237
2308
|
/** Total social users (session-scoped, no cross-dimension dedup needed). */
|
|
2238
|
-
socialUsers:
|
|
2309
|
+
socialUsers: z21.number(),
|
|
2239
2310
|
/** Five disjoint buckets used for the channel breakdown. Known AI session-source matches are removed from their native GA4 bucket before shares are computed. */
|
|
2240
2311
|
channelBreakdown: ga4ChannelBreakdownDtoSchema,
|
|
2241
2312
|
/** Organic sessions as a percentage of total sessions (0–100, rounded). */
|
|
2242
|
-
organicSharePct:
|
|
2313
|
+
organicSharePct: z21.number(),
|
|
2243
2314
|
/** Deduped AI sessions as a percentage of total sessions (0–100, rounded). Cross-cutting: can overlap with Direct/Organic/Social. */
|
|
2244
|
-
aiSharePct:
|
|
2315
|
+
aiSharePct: z21.number(),
|
|
2245
2316
|
/** Session-source-only AI sessions as a percentage of total sessions (0–100, rounded). Can overlap with raw Organic/Social/Direct totals. */
|
|
2246
|
-
aiSharePctBySession:
|
|
2317
|
+
aiSharePctBySession: z21.number(),
|
|
2247
2318
|
/** Direct-channel sessions as a percentage of total sessions (0–100, rounded). */
|
|
2248
|
-
directSharePct:
|
|
2319
|
+
directSharePct: z21.number(),
|
|
2249
2320
|
/** Social sessions as a percentage of total sessions (0–100, rounded). */
|
|
2250
|
-
socialSharePct:
|
|
2321
|
+
socialSharePct: z21.number(),
|
|
2251
2322
|
/** Display string for organicSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
2252
|
-
organicSharePctDisplay:
|
|
2323
|
+
organicSharePctDisplay: z21.string(),
|
|
2253
2324
|
/** Display string for aiSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
2254
|
-
aiSharePctDisplay:
|
|
2325
|
+
aiSharePctDisplay: z21.string(),
|
|
2255
2326
|
/** Display string for aiSharePctBySession: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
2256
|
-
aiSharePctBySessionDisplay:
|
|
2327
|
+
aiSharePctBySessionDisplay: z21.string(),
|
|
2257
2328
|
/** Display string for directSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
2258
|
-
directSharePctDisplay:
|
|
2329
|
+
directSharePctDisplay: z21.string(),
|
|
2259
2330
|
/** Display string for socialSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
2260
|
-
socialSharePctDisplay:
|
|
2331
|
+
socialSharePctDisplay: z21.string(),
|
|
2261
2332
|
/** 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). */
|
|
2262
|
-
otherSessions:
|
|
2333
|
+
otherSessions: z21.number(),
|
|
2263
2334
|
/** Other sessions as a percentage of total sessions (0–100, rounded). */
|
|
2264
|
-
otherSharePct:
|
|
2335
|
+
otherSharePct: z21.number(),
|
|
2265
2336
|
/** Display string for otherSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
|
|
2266
|
-
otherSharePctDisplay:
|
|
2267
|
-
lastSyncedAt:
|
|
2268
|
-
});
|
|
2269
|
-
var ga4StatusDtoSchema =
|
|
2270
|
-
connected:
|
|
2271
|
-
propertyId:
|
|
2272
|
-
clientEmail:
|
|
2273
|
-
authMethod:
|
|
2274
|
-
lastSyncedAt:
|
|
2275
|
-
createdAt:
|
|
2276
|
-
updatedAt:
|
|
2277
|
-
});
|
|
2278
|
-
var ga4SyncResponseDtoSchema =
|
|
2279
|
-
synced:
|
|
2280
|
-
rowCount:
|
|
2281
|
-
aiReferralCount:
|
|
2282
|
-
socialReferralCount:
|
|
2283
|
-
days:
|
|
2284
|
-
syncedAt:
|
|
2337
|
+
otherSharePctDisplay: z21.string(),
|
|
2338
|
+
lastSyncedAt: z21.string().nullable()
|
|
2339
|
+
});
|
|
2340
|
+
var ga4StatusDtoSchema = z21.object({
|
|
2341
|
+
connected: z21.boolean(),
|
|
2342
|
+
propertyId: z21.string().nullable(),
|
|
2343
|
+
clientEmail: z21.string().nullable(),
|
|
2344
|
+
authMethod: z21.enum(["service-account", "oauth"]).nullable(),
|
|
2345
|
+
lastSyncedAt: z21.string().nullable(),
|
|
2346
|
+
createdAt: z21.string().nullable().optional(),
|
|
2347
|
+
updatedAt: z21.string().nullable().optional()
|
|
2348
|
+
});
|
|
2349
|
+
var ga4SyncResponseDtoSchema = z21.object({
|
|
2350
|
+
synced: z21.boolean(),
|
|
2351
|
+
rowCount: z21.number().int().nonnegative(),
|
|
2352
|
+
aiReferralCount: z21.number().int().nonnegative(),
|
|
2353
|
+
socialReferralCount: z21.number().int().nonnegative(),
|
|
2354
|
+
days: z21.number().int().nonnegative(),
|
|
2355
|
+
syncedAt: z21.string(),
|
|
2285
2356
|
/**
|
|
2286
2357
|
* Components that were written this run. Present when `only` is set.
|
|
2287
2358
|
* Always includes `traffic` and `summary` (the share denominator) plus
|
|
2288
2359
|
* the requested channel breakdown — `ai` and/or `social`.
|
|
2289
2360
|
*/
|
|
2290
|
-
syncedComponents:
|
|
2291
|
-
});
|
|
2292
|
-
var ga4AiReferralHistoryEntrySchema =
|
|
2293
|
-
date:
|
|
2294
|
-
source:
|
|
2295
|
-
medium:
|
|
2296
|
-
landingPage:
|
|
2297
|
-
sessions:
|
|
2298
|
-
users:
|
|
2361
|
+
syncedComponents: z21.array(z21.string()).optional()
|
|
2362
|
+
});
|
|
2363
|
+
var ga4AiReferralHistoryEntrySchema = z21.object({
|
|
2364
|
+
date: z21.string(),
|
|
2365
|
+
source: z21.string(),
|
|
2366
|
+
medium: z21.string(),
|
|
2367
|
+
landingPage: z21.string(),
|
|
2368
|
+
sessions: z21.number(),
|
|
2369
|
+
users: z21.number(),
|
|
2299
2370
|
/** Which GA4 dimension this row came from: session (sessionSource), first_user (firstUserSource), or manual_utm (utm_source parameter) */
|
|
2300
2371
|
sourceDimension: ga4SourceDimensionSchema
|
|
2301
2372
|
});
|
|
2302
|
-
var ga4SocialReferralHistoryEntrySchema =
|
|
2303
|
-
date:
|
|
2304
|
-
source:
|
|
2305
|
-
medium:
|
|
2306
|
-
sessions:
|
|
2307
|
-
users:
|
|
2373
|
+
var ga4SocialReferralHistoryEntrySchema = z21.object({
|
|
2374
|
+
date: z21.string(),
|
|
2375
|
+
source: z21.string(),
|
|
2376
|
+
medium: z21.string(),
|
|
2377
|
+
sessions: z21.number(),
|
|
2378
|
+
users: z21.number(),
|
|
2308
2379
|
/** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
|
|
2309
|
-
channelGroup:
|
|
2380
|
+
channelGroup: z21.string()
|
|
2310
2381
|
});
|
|
2311
|
-
var ga4SessionHistoryEntrySchema =
|
|
2312
|
-
date:
|
|
2313
|
-
sessions:
|
|
2314
|
-
organicSessions:
|
|
2315
|
-
users:
|
|
2382
|
+
var ga4SessionHistoryEntrySchema = z21.object({
|
|
2383
|
+
date: z21.string(),
|
|
2384
|
+
sessions: z21.number(),
|
|
2385
|
+
organicSessions: z21.number(),
|
|
2386
|
+
users: z21.number()
|
|
2316
2387
|
});
|
|
2317
2388
|
|
|
2318
2389
|
// ../contracts/src/answer-visibility.ts
|
|
@@ -2480,50 +2551,50 @@ function escapeRegExp(value) {
|
|
|
2480
2551
|
}
|
|
2481
2552
|
|
|
2482
2553
|
// ../contracts/src/agent.ts
|
|
2483
|
-
import { z as
|
|
2484
|
-
var agentProviderIdSchema =
|
|
2485
|
-
var agentProviderOptionDtoSchema =
|
|
2554
|
+
import { z as z22 } from "zod";
|
|
2555
|
+
var agentProviderIdSchema = z22.enum(["claude", "openai", "gemini", "zai"]);
|
|
2556
|
+
var agentProviderOptionDtoSchema = z22.object({
|
|
2486
2557
|
/** Stable identifier — what clients pass back as `provider` on the prompt endpoint. */
|
|
2487
2558
|
id: agentProviderIdSchema,
|
|
2488
2559
|
/** Human-readable label for UI pickers, e.g. "Anthropic (Claude)". */
|
|
2489
|
-
label:
|
|
2560
|
+
label: z22.string(),
|
|
2490
2561
|
/** Default model if the caller doesn't pick one. */
|
|
2491
|
-
defaultModel:
|
|
2562
|
+
defaultModel: z22.string(),
|
|
2492
2563
|
/** Whether a usable API key was found (config.yaml or provider env var). */
|
|
2493
|
-
configured:
|
|
2564
|
+
configured: z22.boolean(),
|
|
2494
2565
|
/**
|
|
2495
2566
|
* Where the key resolved from, if any. `null` when `configured === false`.
|
|
2496
2567
|
* Surfaced so the UI can nudge users toward their preferred source of truth.
|
|
2497
2568
|
*/
|
|
2498
|
-
keySource:
|
|
2569
|
+
keySource: z22.enum(["config", "env"]).nullable()
|
|
2499
2570
|
});
|
|
2500
|
-
var agentProvidersResponseDtoSchema =
|
|
2571
|
+
var agentProvidersResponseDtoSchema = z22.object({
|
|
2501
2572
|
/**
|
|
2502
2573
|
* Every provider Aero knows about. `configured === false` entries are
|
|
2503
2574
|
* included so the UI can render them disabled with an onboarding hint.
|
|
2504
2575
|
*/
|
|
2505
|
-
providers:
|
|
2576
|
+
providers: z22.array(agentProviderOptionDtoSchema).default([]),
|
|
2506
2577
|
/**
|
|
2507
2578
|
* Provider Aero auto-picks when no explicit override is passed. Null if
|
|
2508
2579
|
* nothing is configured (install never exchanged a key).
|
|
2509
2580
|
*/
|
|
2510
2581
|
defaultProvider: agentProviderIdSchema.nullable()
|
|
2511
2582
|
});
|
|
2512
|
-
var memorySourceSchema =
|
|
2583
|
+
var memorySourceSchema = z22.enum(["aero", "user", "compaction"]);
|
|
2513
2584
|
var MemorySources = memorySourceSchema.enum;
|
|
2514
2585
|
var AGENT_MEMORY_VALUE_MAX_BYTES = 2 * 1024;
|
|
2515
2586
|
var AGENT_MEMORY_KEY_MAX_LENGTH = 128;
|
|
2516
|
-
var agentMemoryUpsertRequestSchema =
|
|
2517
|
-
key:
|
|
2518
|
-
value:
|
|
2587
|
+
var agentMemoryUpsertRequestSchema = z22.object({
|
|
2588
|
+
key: z22.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH),
|
|
2589
|
+
value: z22.string().min(1)
|
|
2519
2590
|
});
|
|
2520
|
-
var agentMemoryDeleteRequestSchema =
|
|
2521
|
-
key:
|
|
2591
|
+
var agentMemoryDeleteRequestSchema = z22.object({
|
|
2592
|
+
key: z22.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH)
|
|
2522
2593
|
});
|
|
2523
2594
|
|
|
2524
2595
|
// ../contracts/src/backlinks.ts
|
|
2525
|
-
import { z as
|
|
2526
|
-
var backlinkSourceSchema =
|
|
2596
|
+
import { z as z23 } from "zod";
|
|
2597
|
+
var backlinkSourceSchema = z23.enum(["commoncrawl", "bing-webmaster"]);
|
|
2527
2598
|
var BacklinkSources = backlinkSourceSchema.enum;
|
|
2528
2599
|
function computeBacklinkSummaryMetrics(rows) {
|
|
2529
2600
|
if (rows.length === 0) {
|
|
@@ -2539,148 +2610,148 @@ function computeBacklinkSummaryMetrics(rows) {
|
|
|
2539
2610
|
top10HostsShare: share.toFixed(6)
|
|
2540
2611
|
};
|
|
2541
2612
|
}
|
|
2542
|
-
var ccReleaseSyncStatusSchema =
|
|
2613
|
+
var ccReleaseSyncStatusSchema = z23.enum(["queued", "downloading", "querying", "ready", "failed"]);
|
|
2543
2614
|
var CcReleaseSyncStatuses = ccReleaseSyncStatusSchema.enum;
|
|
2544
|
-
var ccReleaseSyncDtoSchema =
|
|
2545
|
-
id:
|
|
2546
|
-
release:
|
|
2615
|
+
var ccReleaseSyncDtoSchema = z23.object({
|
|
2616
|
+
id: z23.string(),
|
|
2617
|
+
release: z23.string(),
|
|
2547
2618
|
status: ccReleaseSyncStatusSchema,
|
|
2548
|
-
phaseDetail:
|
|
2549
|
-
vertexPath:
|
|
2550
|
-
edgesPath:
|
|
2551
|
-
vertexSha256:
|
|
2552
|
-
edgesSha256:
|
|
2553
|
-
vertexBytes:
|
|
2554
|
-
edgesBytes:
|
|
2555
|
-
projectsProcessed:
|
|
2556
|
-
domainsDiscovered:
|
|
2557
|
-
downloadStartedAt:
|
|
2558
|
-
downloadFinishedAt:
|
|
2559
|
-
queryStartedAt:
|
|
2560
|
-
queryFinishedAt:
|
|
2561
|
-
error:
|
|
2562
|
-
createdAt:
|
|
2563
|
-
updatedAt:
|
|
2564
|
-
});
|
|
2565
|
-
var backlinkDomainDtoSchema =
|
|
2566
|
-
linkingDomain:
|
|
2619
|
+
phaseDetail: z23.string().nullable().optional(),
|
|
2620
|
+
vertexPath: z23.string().nullable().optional(),
|
|
2621
|
+
edgesPath: z23.string().nullable().optional(),
|
|
2622
|
+
vertexSha256: z23.string().nullable().optional(),
|
|
2623
|
+
edgesSha256: z23.string().nullable().optional(),
|
|
2624
|
+
vertexBytes: z23.number().int().nullable().optional(),
|
|
2625
|
+
edgesBytes: z23.number().int().nullable().optional(),
|
|
2626
|
+
projectsProcessed: z23.number().int().nullable().optional(),
|
|
2627
|
+
domainsDiscovered: z23.number().int().nullable().optional(),
|
|
2628
|
+
downloadStartedAt: z23.string().nullable().optional(),
|
|
2629
|
+
downloadFinishedAt: z23.string().nullable().optional(),
|
|
2630
|
+
queryStartedAt: z23.string().nullable().optional(),
|
|
2631
|
+
queryFinishedAt: z23.string().nullable().optional(),
|
|
2632
|
+
error: z23.string().nullable().optional(),
|
|
2633
|
+
createdAt: z23.string(),
|
|
2634
|
+
updatedAt: z23.string()
|
|
2635
|
+
});
|
|
2636
|
+
var backlinkDomainDtoSchema = z23.object({
|
|
2637
|
+
linkingDomain: z23.string(),
|
|
2567
2638
|
// For Common Crawl this is the count of distinct hosts within the linking
|
|
2568
2639
|
// domain; for Bing Webmaster it is the count of distinct linking pages (URLs)
|
|
2569
2640
|
// from that linking host. Read alongside `source` — the unit differs per source.
|
|
2570
|
-
numHosts:
|
|
2641
|
+
numHosts: z23.number().int(),
|
|
2571
2642
|
source: backlinkSourceSchema
|
|
2572
2643
|
});
|
|
2573
|
-
var backlinkSummaryDtoSchema =
|
|
2574
|
-
projectId:
|
|
2644
|
+
var backlinkSummaryDtoSchema = z23.object({
|
|
2645
|
+
projectId: z23.string(),
|
|
2575
2646
|
// Window identifier. Common Crawl uses the release slug
|
|
2576
2647
|
// (`cc-main-YYYY-<mon>-<mon>-<mon>`); Bing Webmaster uses a synthetic
|
|
2577
2648
|
// per-sync-day window (`bing-YYYY-MM-DD`).
|
|
2578
|
-
release:
|
|
2579
|
-
targetDomain:
|
|
2580
|
-
totalLinkingDomains:
|
|
2581
|
-
totalHosts:
|
|
2582
|
-
top10HostsShare:
|
|
2583
|
-
queriedAt:
|
|
2649
|
+
release: z23.string(),
|
|
2650
|
+
targetDomain: z23.string(),
|
|
2651
|
+
totalLinkingDomains: z23.number().int(),
|
|
2652
|
+
totalHosts: z23.number().int(),
|
|
2653
|
+
top10HostsShare: z23.string(),
|
|
2654
|
+
queriedAt: z23.string(),
|
|
2584
2655
|
source: backlinkSourceSchema,
|
|
2585
2656
|
// Populated when the response is filtered (e.g. ?excludeCrawlers=1).
|
|
2586
2657
|
// Counts the rows omitted from totalLinkingDomains/totalHosts so callers
|
|
2587
2658
|
// can show "N hidden" hints without re-deriving them.
|
|
2588
|
-
excludedLinkingDomains:
|
|
2589
|
-
excludedHosts:
|
|
2659
|
+
excludedLinkingDomains: z23.number().int().optional(),
|
|
2660
|
+
excludedHosts: z23.number().int().optional()
|
|
2590
2661
|
});
|
|
2591
|
-
var backlinkListResponseSchema =
|
|
2662
|
+
var backlinkListResponseSchema = z23.object({
|
|
2592
2663
|
// The source this response was filtered to (defaults to commoncrawl when the
|
|
2593
2664
|
// caller omits `?source`).
|
|
2594
2665
|
source: backlinkSourceSchema,
|
|
2595
2666
|
summary: backlinkSummaryDtoSchema.nullable(),
|
|
2596
|
-
total:
|
|
2597
|
-
rows:
|
|
2598
|
-
});
|
|
2599
|
-
var backlinkHistoryEntrySchema =
|
|
2600
|
-
release:
|
|
2601
|
-
totalLinkingDomains:
|
|
2602
|
-
totalHosts:
|
|
2603
|
-
top10HostsShare:
|
|
2604
|
-
queriedAt:
|
|
2667
|
+
total: z23.number().int(),
|
|
2668
|
+
rows: z23.array(backlinkDomainDtoSchema)
|
|
2669
|
+
});
|
|
2670
|
+
var backlinkHistoryEntrySchema = z23.object({
|
|
2671
|
+
release: z23.string(),
|
|
2672
|
+
totalLinkingDomains: z23.number().int(),
|
|
2673
|
+
totalHosts: z23.number().int(),
|
|
2674
|
+
top10HostsShare: z23.string(),
|
|
2675
|
+
queriedAt: z23.string(),
|
|
2605
2676
|
source: backlinkSourceSchema
|
|
2606
2677
|
});
|
|
2607
|
-
var backlinkSourceAvailabilityDtoSchema =
|
|
2678
|
+
var backlinkSourceAvailabilityDtoSchema = z23.object({
|
|
2608
2679
|
source: backlinkSourceSchema,
|
|
2609
2680
|
/**
|
|
2610
2681
|
* The source is set up for this project:
|
|
2611
2682
|
* - commoncrawl: `autoExtractBacklinks` enabled AND a `ready` release sync exists.
|
|
2612
2683
|
* - bing-webmaster: a Bing Webmaster connection exists for the project domain.
|
|
2613
2684
|
*/
|
|
2614
|
-
connected:
|
|
2685
|
+
connected: z23.boolean(),
|
|
2615
2686
|
/** Backlink rows exist for this project + source. */
|
|
2616
|
-
hasData:
|
|
2687
|
+
hasData: z23.boolean(),
|
|
2617
2688
|
/** Latest window id with data for this source, null when none. */
|
|
2618
|
-
latestRelease:
|
|
2689
|
+
latestRelease: z23.string().nullable(),
|
|
2619
2690
|
/**
|
|
2620
2691
|
* Linking-domain count in the latest window. Excludes crawler/proxy hosts only
|
|
2621
2692
|
* when the request sets `?excludeCrawlers=1` (default off, matching the summary
|
|
2622
2693
|
* and domains endpoints); the dashboard passes it so the switcher pill matches
|
|
2623
2694
|
* the metric card.
|
|
2624
2695
|
*/
|
|
2625
|
-
totalLinkingDomains:
|
|
2696
|
+
totalLinkingDomains: z23.number().int(),
|
|
2626
2697
|
/** Freshness: `queriedAt` of the latest summary for this source, null when none. */
|
|
2627
|
-
lastSyncedAt:
|
|
2698
|
+
lastSyncedAt: z23.string().nullable()
|
|
2628
2699
|
});
|
|
2629
|
-
var backlinkSourcesResponseSchema =
|
|
2630
|
-
projectId:
|
|
2631
|
-
targetDomain:
|
|
2700
|
+
var backlinkSourcesResponseSchema = z23.object({
|
|
2701
|
+
projectId: z23.string(),
|
|
2702
|
+
targetDomain: z23.string(),
|
|
2632
2703
|
/** Availability for every known source, in a stable order. */
|
|
2633
|
-
sources:
|
|
2634
|
-
anyConnected:
|
|
2635
|
-
anyData:
|
|
2636
|
-
});
|
|
2637
|
-
var backlinksInstallStatusDtoSchema =
|
|
2638
|
-
duckdbInstalled:
|
|
2639
|
-
duckdbVersion:
|
|
2640
|
-
duckdbSpec:
|
|
2641
|
-
pluginDir:
|
|
2642
|
-
});
|
|
2643
|
-
var backlinksInstallResultDtoSchema =
|
|
2644
|
-
installed:
|
|
2645
|
-
version:
|
|
2646
|
-
path:
|
|
2647
|
-
alreadyPresent:
|
|
2648
|
-
});
|
|
2649
|
-
var ccAvailableReleaseSchema =
|
|
2650
|
-
release:
|
|
2651
|
-
vertexUrl:
|
|
2652
|
-
edgesUrl:
|
|
2653
|
-
vertexBytes:
|
|
2654
|
-
edgesBytes:
|
|
2655
|
-
lastModified:
|
|
2656
|
-
});
|
|
2657
|
-
var ccCachedReleaseSchema =
|
|
2658
|
-
release:
|
|
2704
|
+
sources: z23.array(backlinkSourceAvailabilityDtoSchema),
|
|
2705
|
+
anyConnected: z23.boolean(),
|
|
2706
|
+
anyData: z23.boolean()
|
|
2707
|
+
});
|
|
2708
|
+
var backlinksInstallStatusDtoSchema = z23.object({
|
|
2709
|
+
duckdbInstalled: z23.boolean(),
|
|
2710
|
+
duckdbVersion: z23.string().nullable().optional(),
|
|
2711
|
+
duckdbSpec: z23.string(),
|
|
2712
|
+
pluginDir: z23.string()
|
|
2713
|
+
});
|
|
2714
|
+
var backlinksInstallResultDtoSchema = z23.object({
|
|
2715
|
+
installed: z23.boolean(),
|
|
2716
|
+
version: z23.string(),
|
|
2717
|
+
path: z23.string(),
|
|
2718
|
+
alreadyPresent: z23.boolean()
|
|
2719
|
+
});
|
|
2720
|
+
var ccAvailableReleaseSchema = z23.object({
|
|
2721
|
+
release: z23.string(),
|
|
2722
|
+
vertexUrl: z23.string(),
|
|
2723
|
+
edgesUrl: z23.string(),
|
|
2724
|
+
vertexBytes: z23.number().int().nullable(),
|
|
2725
|
+
edgesBytes: z23.number().int().nullable(),
|
|
2726
|
+
lastModified: z23.string().nullable()
|
|
2727
|
+
});
|
|
2728
|
+
var ccCachedReleaseSchema = z23.object({
|
|
2729
|
+
release: z23.string(),
|
|
2659
2730
|
syncStatus: ccReleaseSyncStatusSchema.nullable(),
|
|
2660
|
-
bytes:
|
|
2661
|
-
lastUsedAt:
|
|
2731
|
+
bytes: z23.number().int(),
|
|
2732
|
+
lastUsedAt: z23.string().nullable()
|
|
2662
2733
|
});
|
|
2663
2734
|
|
|
2664
2735
|
// ../contracts/src/composites.ts
|
|
2665
|
-
import { z as
|
|
2666
|
-
var searchHitKindSchema =
|
|
2667
|
-
var projectSearchSnapshotHitSchema =
|
|
2668
|
-
kind:
|
|
2669
|
-
id:
|
|
2670
|
-
runId:
|
|
2671
|
-
query:
|
|
2672
|
-
provider:
|
|
2673
|
-
model:
|
|
2736
|
+
import { z as z24 } from "zod";
|
|
2737
|
+
var searchHitKindSchema = z24.enum(["snapshot", "insight"]);
|
|
2738
|
+
var projectSearchSnapshotHitSchema = z24.object({
|
|
2739
|
+
kind: z24.literal("snapshot"),
|
|
2740
|
+
id: z24.string(),
|
|
2741
|
+
runId: z24.string(),
|
|
2742
|
+
query: z24.string(),
|
|
2743
|
+
provider: z24.string(),
|
|
2744
|
+
model: z24.string().nullable(),
|
|
2674
2745
|
citationState: citationStateSchema,
|
|
2675
|
-
matchedField:
|
|
2676
|
-
snippet:
|
|
2677
|
-
createdAt:
|
|
2678
|
-
});
|
|
2679
|
-
var projectSearchInsightHitSchema =
|
|
2680
|
-
kind:
|
|
2681
|
-
id:
|
|
2682
|
-
runId:
|
|
2683
|
-
type:
|
|
2746
|
+
matchedField: z24.enum(["answerText", "citedDomains", "searchQueries", "query"]),
|
|
2747
|
+
snippet: z24.string(),
|
|
2748
|
+
createdAt: z24.string()
|
|
2749
|
+
});
|
|
2750
|
+
var projectSearchInsightHitSchema = z24.object({
|
|
2751
|
+
kind: z24.literal("insight"),
|
|
2752
|
+
id: z24.string(),
|
|
2753
|
+
runId: z24.string().nullable(),
|
|
2754
|
+
type: z24.enum([
|
|
2684
2755
|
"regression",
|
|
2685
2756
|
"gain",
|
|
2686
2757
|
"opportunity",
|
|
@@ -2696,29 +2767,29 @@ var projectSearchInsightHitSchema = z23.object({
|
|
|
2696
2767
|
"gbp-metric-drop",
|
|
2697
2768
|
"gbp-keyword-drop"
|
|
2698
2769
|
]),
|
|
2699
|
-
severity:
|
|
2700
|
-
title:
|
|
2701
|
-
query:
|
|
2702
|
-
provider:
|
|
2703
|
-
matchedField:
|
|
2704
|
-
snippet:
|
|
2705
|
-
dismissed:
|
|
2706
|
-
createdAt:
|
|
2707
|
-
});
|
|
2708
|
-
var projectSearchHitSchema =
|
|
2770
|
+
severity: z24.enum(["critical", "high", "medium", "low"]),
|
|
2771
|
+
title: z24.string(),
|
|
2772
|
+
query: z24.string(),
|
|
2773
|
+
provider: z24.string(),
|
|
2774
|
+
matchedField: z24.enum(["title", "query", "recommendation", "cause"]),
|
|
2775
|
+
snippet: z24.string(),
|
|
2776
|
+
dismissed: z24.boolean(),
|
|
2777
|
+
createdAt: z24.string()
|
|
2778
|
+
});
|
|
2779
|
+
var projectSearchHitSchema = z24.discriminatedUnion("kind", [
|
|
2709
2780
|
projectSearchSnapshotHitSchema,
|
|
2710
2781
|
projectSearchInsightHitSchema
|
|
2711
2782
|
]);
|
|
2712
|
-
var projectSearchResponseSchema =
|
|
2713
|
-
query:
|
|
2714
|
-
totalHits:
|
|
2715
|
-
truncated:
|
|
2716
|
-
hits:
|
|
2783
|
+
var projectSearchResponseSchema = z24.object({
|
|
2784
|
+
query: z24.string(),
|
|
2785
|
+
totalHits: z24.number().int().nonnegative(),
|
|
2786
|
+
truncated: z24.boolean(),
|
|
2787
|
+
hits: z24.array(projectSearchHitSchema)
|
|
2717
2788
|
});
|
|
2718
2789
|
|
|
2719
2790
|
// ../contracts/src/content.ts
|
|
2720
|
-
import { z as
|
|
2721
|
-
var contentActionSchema =
|
|
2791
|
+
import { z as z25 } from "zod";
|
|
2792
|
+
var contentActionSchema = z25.enum(["create", "expand", "refresh", "add-schema"]);
|
|
2722
2793
|
var ContentActions = contentActionSchema.enum;
|
|
2723
2794
|
function contentActionLabel(action) {
|
|
2724
2795
|
switch (action) {
|
|
@@ -2732,9 +2803,9 @@ function contentActionLabel(action) {
|
|
|
2732
2803
|
return "Add schema";
|
|
2733
2804
|
}
|
|
2734
2805
|
}
|
|
2735
|
-
var demandSourceSchema =
|
|
2806
|
+
var demandSourceSchema = z25.enum(["gsc", "competitor-evidence", "both"]);
|
|
2736
2807
|
var DemandSources = demandSourceSchema.enum;
|
|
2737
|
-
var actionConfidenceSchema =
|
|
2808
|
+
var actionConfidenceSchema = z25.enum(["high", "medium", "low"]);
|
|
2738
2809
|
var ActionConfidences = actionConfidenceSchema.enum;
|
|
2739
2810
|
function actionConfidenceLabel(confidence) {
|
|
2740
2811
|
switch (confidence) {
|
|
@@ -2746,7 +2817,7 @@ function actionConfidenceLabel(confidence) {
|
|
|
2746
2817
|
return "Low";
|
|
2747
2818
|
}
|
|
2748
2819
|
}
|
|
2749
|
-
var pageTypeSchema =
|
|
2820
|
+
var pageTypeSchema = z25.enum([
|
|
2750
2821
|
"blog-post",
|
|
2751
2822
|
"comparison",
|
|
2752
2823
|
"listicle",
|
|
@@ -2755,7 +2826,7 @@ var pageTypeSchema = z24.enum([
|
|
|
2755
2826
|
"glossary"
|
|
2756
2827
|
]);
|
|
2757
2828
|
var PageTypes = pageTypeSchema.enum;
|
|
2758
|
-
var contentActionStateSchema =
|
|
2829
|
+
var contentActionStateSchema = z25.enum([
|
|
2759
2830
|
"proposed",
|
|
2760
2831
|
"briefed",
|
|
2761
2832
|
"payload-generated",
|
|
@@ -2765,7 +2836,7 @@ var contentActionStateSchema = z24.enum([
|
|
|
2765
2836
|
"dismissed"
|
|
2766
2837
|
]);
|
|
2767
2838
|
var ContentActionStates = contentActionStateSchema.enum;
|
|
2768
|
-
var winnabilityClassSchema =
|
|
2839
|
+
var winnabilityClassSchema = z25.enum(["ownable", "ceded"]);
|
|
2769
2840
|
var WinnabilityClasses = winnabilityClassSchema.enum;
|
|
2770
2841
|
function winnabilityClassLabel(winnabilityClass) {
|
|
2771
2842
|
switch (winnabilityClass) {
|
|
@@ -2800,40 +2871,40 @@ function deriveWinnabilityClass(citedSurfaceDomains, surfaceClasses, threshold =
|
|
|
2800
2871
|
winnability
|
|
2801
2872
|
};
|
|
2802
2873
|
}
|
|
2803
|
-
var ourBestPageSchema =
|
|
2804
|
-
url:
|
|
2805
|
-
gscImpressions:
|
|
2806
|
-
gscClicks:
|
|
2874
|
+
var ourBestPageSchema = z25.object({
|
|
2875
|
+
url: z25.string(),
|
|
2876
|
+
gscImpressions: z25.number().nonnegative(),
|
|
2877
|
+
gscClicks: z25.number().nonnegative(),
|
|
2807
2878
|
// Null when the page came from the inventory fallback (no GSC ranking data).
|
|
2808
|
-
gscAvgPosition:
|
|
2809
|
-
organicSessions:
|
|
2879
|
+
gscAvgPosition: z25.number().nonnegative().nullable(),
|
|
2880
|
+
organicSessions: z25.number().nonnegative()
|
|
2810
2881
|
});
|
|
2811
|
-
var winningCompetitorSchema =
|
|
2812
|
-
domain:
|
|
2813
|
-
url:
|
|
2814
|
-
title:
|
|
2815
|
-
citationCount:
|
|
2882
|
+
var winningCompetitorSchema = z25.object({
|
|
2883
|
+
domain: z25.string(),
|
|
2884
|
+
url: z25.string(),
|
|
2885
|
+
title: z25.string(),
|
|
2886
|
+
citationCount: z25.number().int().nonnegative()
|
|
2816
2887
|
});
|
|
2817
|
-
var scoreBreakdownSchema =
|
|
2818
|
-
demand:
|
|
2819
|
-
competitor:
|
|
2820
|
-
absence:
|
|
2821
|
-
gapSeverity:
|
|
2888
|
+
var scoreBreakdownSchema = z25.object({
|
|
2889
|
+
demand: z25.number(),
|
|
2890
|
+
competitor: z25.number(),
|
|
2891
|
+
absence: z25.number(),
|
|
2892
|
+
gapSeverity: z25.number()
|
|
2822
2893
|
});
|
|
2823
|
-
var existingActionRefSchema =
|
|
2824
|
-
actionId:
|
|
2894
|
+
var existingActionRefSchema = z25.object({
|
|
2895
|
+
actionId: z25.string(),
|
|
2825
2896
|
state: contentActionStateSchema,
|
|
2826
|
-
lastUpdated:
|
|
2897
|
+
lastUpdated: z25.string()
|
|
2827
2898
|
});
|
|
2828
|
-
var contentTargetRowDtoSchema =
|
|
2829
|
-
targetRef:
|
|
2830
|
-
query:
|
|
2899
|
+
var contentTargetRowDtoSchema = z25.object({
|
|
2900
|
+
targetRef: z25.string(),
|
|
2901
|
+
query: z25.string(),
|
|
2831
2902
|
action: contentActionSchema,
|
|
2832
2903
|
ourBestPage: ourBestPageSchema.nullable(),
|
|
2833
2904
|
winningCompetitor: winningCompetitorSchema.nullable(),
|
|
2834
|
-
score:
|
|
2905
|
+
score: z25.number(),
|
|
2835
2906
|
scoreBreakdown: scoreBreakdownSchema,
|
|
2836
|
-
drivers:
|
|
2907
|
+
drivers: z25.array(z25.string()),
|
|
2837
2908
|
demandSource: demandSourceSchema,
|
|
2838
2909
|
actionConfidence: actionConfidenceSchema,
|
|
2839
2910
|
existingAction: existingActionRefSchema.nullable(),
|
|
@@ -2848,134 +2919,134 @@ var contentTargetRowDtoSchema = z24.object({
|
|
|
2848
2919
|
* `[0, 1]`. `null` when the gate failed open (no classification coverage for
|
|
2849
2920
|
* the cited surface) — distinct from a computed `1.0`.
|
|
2850
2921
|
*/
|
|
2851
|
-
winnability:
|
|
2852
|
-
});
|
|
2853
|
-
var contentTargetsResponseDtoSchema =
|
|
2854
|
-
targets:
|
|
2855
|
-
contextMetrics:
|
|
2856
|
-
totalAiReferralSessions:
|
|
2857
|
-
latestRunId:
|
|
2858
|
-
runTimestamp:
|
|
2922
|
+
winnability: z25.number().min(0).max(1).nullable()
|
|
2923
|
+
});
|
|
2924
|
+
var contentTargetsResponseDtoSchema = z25.object({
|
|
2925
|
+
targets: z25.array(contentTargetRowDtoSchema),
|
|
2926
|
+
contextMetrics: z25.object({
|
|
2927
|
+
totalAiReferralSessions: z25.number().int().nonnegative(),
|
|
2928
|
+
latestRunId: z25.string(),
|
|
2929
|
+
runTimestamp: z25.string()
|
|
2859
2930
|
})
|
|
2860
2931
|
});
|
|
2861
|
-
var contentTargetDismissalDtoSchema =
|
|
2862
|
-
targetRef:
|
|
2863
|
-
addressedUrl:
|
|
2864
|
-
note:
|
|
2865
|
-
dismissedAt:
|
|
2932
|
+
var contentTargetDismissalDtoSchema = z25.object({
|
|
2933
|
+
targetRef: z25.string(),
|
|
2934
|
+
addressedUrl: z25.string().nullable(),
|
|
2935
|
+
note: z25.string().nullable(),
|
|
2936
|
+
dismissedAt: z25.string()
|
|
2866
2937
|
});
|
|
2867
|
-
var contentTargetDismissalsResponseDtoSchema =
|
|
2868
|
-
dismissals:
|
|
2938
|
+
var contentTargetDismissalsResponseDtoSchema = z25.object({
|
|
2939
|
+
dismissals: z25.array(contentTargetDismissalDtoSchema)
|
|
2869
2940
|
});
|
|
2870
|
-
var contentTargetDismissRequestSchema =
|
|
2871
|
-
targetRef:
|
|
2941
|
+
var contentTargetDismissRequestSchema = z25.object({
|
|
2942
|
+
targetRef: z25.string().min(1),
|
|
2872
2943
|
/** 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. */
|
|
2873
|
-
addressedUrl:
|
|
2944
|
+
addressedUrl: z25.string().url().optional(),
|
|
2874
2945
|
/** Free-form note (e.g. "covered in our Q1 content sprint"). 500 char cap is the API surface limit; the DB column is unbounded. */
|
|
2875
|
-
note:
|
|
2946
|
+
note: z25.string().max(500).optional()
|
|
2876
2947
|
});
|
|
2877
|
-
var recommendationExplanationDtoSchema =
|
|
2878
|
-
targetRef:
|
|
2948
|
+
var recommendationExplanationDtoSchema = z25.object({
|
|
2949
|
+
targetRef: z25.string(),
|
|
2879
2950
|
/** Version of the prompt template used. Bumping the version invalidates the cache forward without touching the table. */
|
|
2880
|
-
promptVersion:
|
|
2951
|
+
promptVersion: z25.string(),
|
|
2881
2952
|
/** Provider that produced the explanation (e.g. "claude", "gemini"). */
|
|
2882
|
-
provider:
|
|
2953
|
+
provider: z25.string(),
|
|
2883
2954
|
/** Model id within that provider (e.g. "claude-sonnet-4-6"). */
|
|
2884
|
-
model:
|
|
2955
|
+
model: z25.string(),
|
|
2885
2956
|
/** Markdown-formatted rationale + recommended next steps. */
|
|
2886
|
-
responseText:
|
|
2957
|
+
responseText: z25.string(),
|
|
2887
2958
|
/** Estimated cost in millicents (1/100 of a cent). 0 when unknown. */
|
|
2888
|
-
costMillicents:
|
|
2889
|
-
generatedAt:
|
|
2959
|
+
costMillicents: z25.number().int().nonnegative(),
|
|
2960
|
+
generatedAt: z25.string()
|
|
2890
2961
|
});
|
|
2891
|
-
var recommendationExplainRequestSchema =
|
|
2962
|
+
var recommendationExplainRequestSchema = z25.object({
|
|
2892
2963
|
/**
|
|
2893
2964
|
* Optional provider override (e.g. "claude" to force Claude even if
|
|
2894
2965
|
* the project's default is Gemini). Falls through to project default
|
|
2895
2966
|
* → auto-detect when omitted.
|
|
2896
2967
|
*/
|
|
2897
|
-
provider:
|
|
2968
|
+
provider: z25.string().optional(),
|
|
2898
2969
|
/**
|
|
2899
2970
|
* Optional model override within the chosen provider. Falls through to
|
|
2900
2971
|
* the `analyze`-tier default model when omitted.
|
|
2901
2972
|
*/
|
|
2902
|
-
model:
|
|
2973
|
+
model: z25.string().optional(),
|
|
2903
2974
|
/**
|
|
2904
2975
|
* Force a fresh LLM call even if a cached explanation exists for the
|
|
2905
2976
|
* current prompt version. Use sparingly — defeats the cache.
|
|
2906
2977
|
*/
|
|
2907
|
-
forceRefresh:
|
|
2978
|
+
forceRefresh: z25.boolean().optional()
|
|
2908
2979
|
});
|
|
2909
|
-
var contentBriefDtoSchema =
|
|
2980
|
+
var contentBriefDtoSchema = z25.object({
|
|
2910
2981
|
/** The query the brief is for (echoed from the recommendation). */
|
|
2911
|
-
targetQuery:
|
|
2982
|
+
targetQuery: z25.string().trim().min(1),
|
|
2912
2983
|
/** Always `ownable` in practice — the gate rejects `ceded` before synthesis. */
|
|
2913
2984
|
winnabilityClass: winnabilityClassSchema,
|
|
2914
2985
|
/** The differentiated content angle to take. */
|
|
2915
|
-
angle:
|
|
2986
|
+
angle: z25.string().trim().min(1),
|
|
2916
2987
|
/** Why this query is winnable, citing the cited-surface signal. */
|
|
2917
|
-
whyWinnable:
|
|
2988
|
+
whyWinnable: z25.string().trim().min(1),
|
|
2918
2989
|
/** The schema.org type or markup to add or extend. */
|
|
2919
|
-
schemaHookup:
|
|
2990
|
+
schemaHookup: z25.string().trim().min(1),
|
|
2920
2991
|
/** Why the cited surface is controllable (the ownable-vs-ceded reasoning). */
|
|
2921
|
-
controllableSurfaceRationale:
|
|
2992
|
+
controllableSurfaceRationale: z25.string().trim().min(1)
|
|
2922
2993
|
});
|
|
2923
|
-
var recommendationBriefDtoSchema =
|
|
2924
|
-
targetRef:
|
|
2994
|
+
var recommendationBriefDtoSchema = z25.object({
|
|
2995
|
+
targetRef: z25.string(),
|
|
2925
2996
|
/** Version of the brief prompt template; bumping invalidates the cache forward. */
|
|
2926
|
-
promptVersion:
|
|
2927
|
-
provider:
|
|
2928
|
-
model:
|
|
2997
|
+
promptVersion: z25.string(),
|
|
2998
|
+
provider: z25.string(),
|
|
2999
|
+
model: z25.string(),
|
|
2929
3000
|
brief: contentBriefDtoSchema,
|
|
2930
3001
|
/** Estimated cost in millicents (1/100 of a cent). 0 when unknown. */
|
|
2931
|
-
costMillicents:
|
|
2932
|
-
generatedAt:
|
|
3002
|
+
costMillicents: z25.number().int().nonnegative(),
|
|
3003
|
+
generatedAt: z25.string()
|
|
2933
3004
|
});
|
|
2934
|
-
var domainClassificationDtoSchema =
|
|
2935
|
-
domain:
|
|
3005
|
+
var domainClassificationDtoSchema = z25.object({
|
|
3006
|
+
domain: z25.string(),
|
|
2936
3007
|
competitorType: discoveryCompetitorTypeSchema,
|
|
2937
|
-
hits:
|
|
2938
|
-
updatedAt:
|
|
3008
|
+
hits: z25.number().int().nonnegative(),
|
|
3009
|
+
updatedAt: z25.string()
|
|
2939
3010
|
});
|
|
2940
|
-
var domainClassificationsResponseDtoSchema =
|
|
2941
|
-
classifications:
|
|
3011
|
+
var domainClassificationsResponseDtoSchema = z25.object({
|
|
3012
|
+
classifications: z25.array(domainClassificationDtoSchema)
|
|
2942
3013
|
});
|
|
2943
|
-
var contentGroundingSourceSchema =
|
|
2944
|
-
uri:
|
|
2945
|
-
title:
|
|
2946
|
-
domain:
|
|
2947
|
-
isOurDomain:
|
|
2948
|
-
isCompetitor:
|
|
2949
|
-
citationCount:
|
|
2950
|
-
providers:
|
|
2951
|
-
});
|
|
2952
|
-
var contentSourceRowDtoSchema =
|
|
2953
|
-
query:
|
|
2954
|
-
groundingSources:
|
|
2955
|
-
});
|
|
2956
|
-
var contentSourcesResponseDtoSchema =
|
|
2957
|
-
sources:
|
|
2958
|
-
latestRunId:
|
|
2959
|
-
});
|
|
2960
|
-
var contentGapRowDtoSchema =
|
|
2961
|
-
query:
|
|
2962
|
-
competitorDomains:
|
|
2963
|
-
competitorCount:
|
|
2964
|
-
missRate:
|
|
2965
|
-
lastSeenInRunId:
|
|
2966
|
-
});
|
|
2967
|
-
var contentGapsResponseDtoSchema =
|
|
2968
|
-
gaps:
|
|
2969
|
-
latestRunId:
|
|
3014
|
+
var contentGroundingSourceSchema = z25.object({
|
|
3015
|
+
uri: z25.string(),
|
|
3016
|
+
title: z25.string(),
|
|
3017
|
+
domain: z25.string(),
|
|
3018
|
+
isOurDomain: z25.boolean(),
|
|
3019
|
+
isCompetitor: z25.boolean(),
|
|
3020
|
+
citationCount: z25.number().int().nonnegative(),
|
|
3021
|
+
providers: z25.array(providerNameSchema)
|
|
3022
|
+
});
|
|
3023
|
+
var contentSourceRowDtoSchema = z25.object({
|
|
3024
|
+
query: z25.string(),
|
|
3025
|
+
groundingSources: z25.array(contentGroundingSourceSchema)
|
|
3026
|
+
});
|
|
3027
|
+
var contentSourcesResponseDtoSchema = z25.object({
|
|
3028
|
+
sources: z25.array(contentSourceRowDtoSchema),
|
|
3029
|
+
latestRunId: z25.string()
|
|
3030
|
+
});
|
|
3031
|
+
var contentGapRowDtoSchema = z25.object({
|
|
3032
|
+
query: z25.string(),
|
|
3033
|
+
competitorDomains: z25.array(z25.string()),
|
|
3034
|
+
competitorCount: z25.number().int().nonnegative(),
|
|
3035
|
+
missRate: z25.number().min(0).max(1),
|
|
3036
|
+
lastSeenInRunId: z25.string()
|
|
3037
|
+
});
|
|
3038
|
+
var contentGapsResponseDtoSchema = z25.object({
|
|
3039
|
+
gaps: z25.array(contentGapRowDtoSchema),
|
|
3040
|
+
latestRunId: z25.string()
|
|
2970
3041
|
});
|
|
2971
3042
|
|
|
2972
3043
|
// ../contracts/src/doctor.ts
|
|
2973
|
-
import { z as
|
|
2974
|
-
var checkStatusSchema =
|
|
3044
|
+
import { z as z26 } from "zod";
|
|
3045
|
+
var checkStatusSchema = z26.enum(["ok", "warn", "fail", "skipped"]);
|
|
2975
3046
|
var CheckStatuses = checkStatusSchema.enum;
|
|
2976
|
-
var checkScopeSchema =
|
|
3047
|
+
var checkScopeSchema = z26.enum(["global", "project"]);
|
|
2977
3048
|
var CheckScopes = checkScopeSchema.enum;
|
|
2978
|
-
var checkCategorySchema =
|
|
3049
|
+
var checkCategorySchema = z26.enum([
|
|
2979
3050
|
"auth",
|
|
2980
3051
|
"config",
|
|
2981
3052
|
"providers",
|
|
@@ -2986,31 +3057,31 @@ var checkCategorySchema = z25.enum([
|
|
|
2986
3057
|
"agent"
|
|
2987
3058
|
]);
|
|
2988
3059
|
var CheckCategories = checkCategorySchema.enum;
|
|
2989
|
-
var checkResultSchema =
|
|
2990
|
-
id:
|
|
3060
|
+
var checkResultSchema = z26.object({
|
|
3061
|
+
id: z26.string(),
|
|
2991
3062
|
category: checkCategorySchema,
|
|
2992
3063
|
scope: checkScopeSchema,
|
|
2993
|
-
title:
|
|
3064
|
+
title: z26.string(),
|
|
2994
3065
|
status: checkStatusSchema,
|
|
2995
|
-
code:
|
|
2996
|
-
summary:
|
|
2997
|
-
remediation:
|
|
2998
|
-
details:
|
|
2999
|
-
durationMs:
|
|
3066
|
+
code: z26.string().describe('Stable machine-readable code (e.g. "google.token.refresh-failed"). Use this for filtering and remediation logic.'),
|
|
3067
|
+
summary: z26.string(),
|
|
3068
|
+
remediation: z26.string().nullable().optional().describe('Operator-facing next step. Null when status is "ok" or no specific remediation applies.'),
|
|
3069
|
+
details: z26.record(z26.string(), z26.unknown()).optional().describe("Structured context \u2014 principal email, redirect URI, missing scopes, etc. Stable per check id."),
|
|
3070
|
+
durationMs: z26.number().int().nonnegative().describe("How long the check took to execute.")
|
|
3000
3071
|
});
|
|
3001
|
-
var doctorReportSchema =
|
|
3072
|
+
var doctorReportSchema = z26.object({
|
|
3002
3073
|
scope: checkScopeSchema,
|
|
3003
|
-
project:
|
|
3004
|
-
generatedAt:
|
|
3005
|
-
durationMs:
|
|
3006
|
-
summary:
|
|
3007
|
-
total:
|
|
3008
|
-
ok:
|
|
3009
|
-
warn:
|
|
3010
|
-
fail:
|
|
3011
|
-
skipped:
|
|
3074
|
+
project: z26.string().nullable().describe('Project name when scope is "project", null otherwise.'),
|
|
3075
|
+
generatedAt: z26.string().describe("ISO-8601 timestamp when this doctor run started."),
|
|
3076
|
+
durationMs: z26.number().int().nonnegative(),
|
|
3077
|
+
summary: z26.object({
|
|
3078
|
+
total: z26.number().int().nonnegative(),
|
|
3079
|
+
ok: z26.number().int().nonnegative(),
|
|
3080
|
+
warn: z26.number().int().nonnegative(),
|
|
3081
|
+
fail: z26.number().int().nonnegative(),
|
|
3082
|
+
skipped: z26.number().int().nonnegative()
|
|
3012
3083
|
}),
|
|
3013
|
-
checks:
|
|
3084
|
+
checks: z26.array(checkResultSchema)
|
|
3014
3085
|
});
|
|
3015
3086
|
function summarizeCheckResults(results) {
|
|
3016
3087
|
const summary = { total: results.length, ok: 0, warn: 0, fail: 0, skipped: 0 };
|
|
@@ -3167,52 +3238,52 @@ function normalizeUrlPath(input) {
|
|
|
3167
3238
|
}
|
|
3168
3239
|
|
|
3169
3240
|
// ../contracts/src/citations.ts
|
|
3170
|
-
import { z as
|
|
3171
|
-
var citationCoverageProviderSchema =
|
|
3172
|
-
provider:
|
|
3241
|
+
import { z as z27 } from "zod";
|
|
3242
|
+
var citationCoverageProviderSchema = z27.object({
|
|
3243
|
+
provider: z27.string(),
|
|
3173
3244
|
citationState: citationStateSchema,
|
|
3174
|
-
cited:
|
|
3175
|
-
mentioned:
|
|
3176
|
-
runId:
|
|
3177
|
-
runCreatedAt:
|
|
3178
|
-
});
|
|
3179
|
-
var citationCoverageRowSchema =
|
|
3180
|
-
queryId:
|
|
3181
|
-
query:
|
|
3182
|
-
providers:
|
|
3183
|
-
citedCount:
|
|
3184
|
-
mentionedCount:
|
|
3185
|
-
totalProviders:
|
|
3186
|
-
});
|
|
3187
|
-
var competitorGapRowSchema =
|
|
3188
|
-
queryId:
|
|
3189
|
-
query:
|
|
3190
|
-
provider:
|
|
3191
|
-
citingCompetitors:
|
|
3192
|
-
runId:
|
|
3193
|
-
runCreatedAt:
|
|
3194
|
-
});
|
|
3195
|
-
var citationVisibilitySummarySchema =
|
|
3196
|
-
providersConfigured:
|
|
3197
|
-
providersCiting:
|
|
3198
|
-
providersMentioning:
|
|
3199
|
-
totalQueries:
|
|
3245
|
+
cited: z27.boolean(),
|
|
3246
|
+
mentioned: z27.boolean(),
|
|
3247
|
+
runId: z27.string(),
|
|
3248
|
+
runCreatedAt: z27.string()
|
|
3249
|
+
});
|
|
3250
|
+
var citationCoverageRowSchema = z27.object({
|
|
3251
|
+
queryId: z27.string(),
|
|
3252
|
+
query: z27.string(),
|
|
3253
|
+
providers: z27.array(citationCoverageProviderSchema),
|
|
3254
|
+
citedCount: z27.number().int().nonnegative(),
|
|
3255
|
+
mentionedCount: z27.number().int().nonnegative(),
|
|
3256
|
+
totalProviders: z27.number().int().nonnegative()
|
|
3257
|
+
});
|
|
3258
|
+
var competitorGapRowSchema = z27.object({
|
|
3259
|
+
queryId: z27.string(),
|
|
3260
|
+
query: z27.string(),
|
|
3261
|
+
provider: z27.string(),
|
|
3262
|
+
citingCompetitors: z27.array(z27.string()),
|
|
3263
|
+
runId: z27.string(),
|
|
3264
|
+
runCreatedAt: z27.string()
|
|
3265
|
+
});
|
|
3266
|
+
var citationVisibilitySummarySchema = z27.object({
|
|
3267
|
+
providersConfigured: z27.number().int().nonnegative(),
|
|
3268
|
+
providersCiting: z27.number().int().nonnegative(),
|
|
3269
|
+
providersMentioning: z27.number().int().nonnegative(),
|
|
3270
|
+
totalQueries: z27.number().int().nonnegative(),
|
|
3200
3271
|
// Cross-tab buckets — each tracked query with at least one snapshot lands
|
|
3201
3272
|
// in exactly one of these. Queries with zero snapshots are not counted in
|
|
3202
3273
|
// any bucket; (sum of buckets) ≤ totalQueries.
|
|
3203
|
-
queriesCitedAndMentioned:
|
|
3204
|
-
queriesCitedOnly:
|
|
3205
|
-
queriesMentionedOnly:
|
|
3206
|
-
queriesInvisible:
|
|
3207
|
-
latestRunId:
|
|
3208
|
-
latestRunAt:
|
|
3209
|
-
});
|
|
3210
|
-
var citationVisibilityResponseSchema =
|
|
3274
|
+
queriesCitedAndMentioned: z27.number().int().nonnegative(),
|
|
3275
|
+
queriesCitedOnly: z27.number().int().nonnegative(),
|
|
3276
|
+
queriesMentionedOnly: z27.number().int().nonnegative(),
|
|
3277
|
+
queriesInvisible: z27.number().int().nonnegative(),
|
|
3278
|
+
latestRunId: z27.string().nullable(),
|
|
3279
|
+
latestRunAt: z27.string().nullable()
|
|
3280
|
+
});
|
|
3281
|
+
var citationVisibilityResponseSchema = z27.object({
|
|
3211
3282
|
summary: citationVisibilitySummarySchema,
|
|
3212
|
-
byQuery:
|
|
3213
|
-
competitorGaps:
|
|
3214
|
-
status:
|
|
3215
|
-
reason:
|
|
3283
|
+
byQuery: z27.array(citationCoverageRowSchema),
|
|
3284
|
+
competitorGaps: z27.array(competitorGapRowSchema),
|
|
3285
|
+
status: z27.enum(["ready", "no-data"]),
|
|
3286
|
+
reason: z27.enum(["no-runs-yet", "no-queries"]).optional()
|
|
3216
3287
|
});
|
|
3217
3288
|
function emptyCitationVisibility(reason) {
|
|
3218
3289
|
return {
|
|
@@ -3239,46 +3310,46 @@ function citationStateToCited(state) {
|
|
|
3239
3310
|
}
|
|
3240
3311
|
|
|
3241
3312
|
// ../contracts/src/report.ts
|
|
3242
|
-
import { z as
|
|
3243
|
-
var providerLocationTreatmentSchema =
|
|
3313
|
+
import { z as z28 } from "zod";
|
|
3314
|
+
var providerLocationTreatmentSchema = z28.enum([
|
|
3244
3315
|
"prompt",
|
|
3245
3316
|
"request-param",
|
|
3246
3317
|
"browser-geo",
|
|
3247
3318
|
"ignored"
|
|
3248
3319
|
]);
|
|
3249
|
-
var reportMetaLocationSchema =
|
|
3320
|
+
var reportMetaLocationSchema = z28.object({
|
|
3250
3321
|
/** Human-readable label as configured on the project (e.g. "michigan"). */
|
|
3251
|
-
label:
|
|
3322
|
+
label: z28.string(),
|
|
3252
3323
|
/** Resolved city/region/country from the project's `LocationContext`. */
|
|
3253
|
-
city:
|
|
3254
|
-
region:
|
|
3255
|
-
country:
|
|
3324
|
+
city: z28.string(),
|
|
3325
|
+
region: z28.string(),
|
|
3326
|
+
country: z28.string(),
|
|
3256
3327
|
/**
|
|
3257
3328
|
* Other locations configured on the project that did NOT power this report.
|
|
3258
3329
|
* When non-empty, callers should make clear that the report is location-scoped:
|
|
3259
3330
|
* a separate sweep is needed to see how AI engines respond from each one.
|
|
3260
3331
|
*/
|
|
3261
|
-
otherConfiguredLabels:
|
|
3332
|
+
otherConfiguredLabels: z28.array(z28.string())
|
|
3262
3333
|
});
|
|
3263
|
-
var reportProviderLocationHandlingSchema =
|
|
3334
|
+
var reportProviderLocationHandlingSchema = z28.object({
|
|
3264
3335
|
/** Provider name (matches `query_snapshots.provider`). */
|
|
3265
|
-
provider:
|
|
3336
|
+
provider: z28.string(),
|
|
3266
3337
|
/** How this provider applied the configured location during this run. */
|
|
3267
3338
|
treatment: providerLocationTreatmentSchema,
|
|
3268
3339
|
/** One-sentence explanation suitable for the report. */
|
|
3269
|
-
description:
|
|
3340
|
+
description: z28.string()
|
|
3270
3341
|
});
|
|
3271
|
-
var reportMetaSchema =
|
|
3342
|
+
var reportMetaSchema = z28.object({
|
|
3272
3343
|
/** ISO timestamp the report was generated (server clock). */
|
|
3273
|
-
generatedAt:
|
|
3344
|
+
generatedAt: z28.string(),
|
|
3274
3345
|
/** Project the report covers. */
|
|
3275
|
-
project:
|
|
3276
|
-
id:
|
|
3277
|
-
name:
|
|
3278
|
-
displayName:
|
|
3279
|
-
canonicalDomain:
|
|
3280
|
-
country:
|
|
3281
|
-
language:
|
|
3346
|
+
project: z28.object({
|
|
3347
|
+
id: z28.string(),
|
|
3348
|
+
name: z28.string(),
|
|
3349
|
+
displayName: z28.string(),
|
|
3350
|
+
canonicalDomain: z28.string(),
|
|
3351
|
+
country: z28.string(),
|
|
3352
|
+
language: z28.string()
|
|
3282
3353
|
}),
|
|
3283
3354
|
/**
|
|
3284
3355
|
* The location that powered the latest visibility run, when one was set.
|
|
@@ -3293,24 +3364,24 @@ var reportMetaSchema = z27.object({
|
|
|
3293
3364
|
* each provider's answer — some providers append it to the prompt, some
|
|
3294
3365
|
* pass it as a structured request field, and some (CDP) ignore it.
|
|
3295
3366
|
*/
|
|
3296
|
-
providerLocationHandling:
|
|
3367
|
+
providerLocationHandling: z28.array(reportProviderLocationHandlingSchema),
|
|
3297
3368
|
/** Earliest data point referenced by the report (ISO date). */
|
|
3298
|
-
periodStart:
|
|
3369
|
+
periodStart: z28.string().nullable(),
|
|
3299
3370
|
/** Latest data point referenced by the report (ISO date). */
|
|
3300
|
-
periodEnd:
|
|
3371
|
+
periodEnd: z28.string().nullable()
|
|
3301
3372
|
});
|
|
3302
|
-
var reportExecutiveSummarySchema =
|
|
3373
|
+
var reportExecutiveSummarySchema = z28.object({
|
|
3303
3374
|
/**
|
|
3304
3375
|
* 0..100 — share of tracked queries that were cited by at least one
|
|
3305
3376
|
* provider in the latest run. "Cited" means the project's domain appeared
|
|
3306
3377
|
* in the source list / grounding the AI used to answer. Computed per-query
|
|
3307
3378
|
* (not per-(query × provider)) so the rate is invariant to provider count.
|
|
3308
3379
|
*/
|
|
3309
|
-
citationRate:
|
|
3380
|
+
citationRate: z28.number(),
|
|
3310
3381
|
/** Numerator of `citationRate` — distinct tracked queries cited by ≥1 provider in the latest run. */
|
|
3311
|
-
citedQueryCount:
|
|
3382
|
+
citedQueryCount: z28.number(),
|
|
3312
3383
|
/** Denominator of `citationRate` — total tracked queries. */
|
|
3313
|
-
totalQueryCount:
|
|
3384
|
+
totalQueryCount: z28.number(),
|
|
3314
3385
|
/**
|
|
3315
3386
|
* 0..100 — share of tracked queries where the project's brand or domain
|
|
3316
3387
|
* appeared in at least one provider's answer text in the latest run.
|
|
@@ -3318,68 +3389,68 @@ var reportExecutiveSummarySchema = z27.object({
|
|
|
3318
3389
|
* the prose without citing your domain in its sources, and vice versa.
|
|
3319
3390
|
* Same per-query denominator as `citationRate` for consistency.
|
|
3320
3391
|
*/
|
|
3321
|
-
mentionRate:
|
|
3392
|
+
mentionRate: z28.number(),
|
|
3322
3393
|
/** Numerator of `mentionRate` — distinct tracked queries mentioned in ≥1 provider's answer text. */
|
|
3323
|
-
mentionedQueryCount:
|
|
3394
|
+
mentionedQueryCount: z28.number(),
|
|
3324
3395
|
/** Compared to the previous run: 'up' | 'down' | 'flat' | 'unknown' (no prior run). */
|
|
3325
|
-
trend:
|
|
3396
|
+
trend: z28.enum(["up", "down", "flat", "unknown"]),
|
|
3326
3397
|
/** Total tracked queries. */
|
|
3327
|
-
queryCount:
|
|
3398
|
+
queryCount: z28.number(),
|
|
3328
3399
|
/** Total tracked competitors. */
|
|
3329
|
-
competitorCount:
|
|
3400
|
+
competitorCount: z28.number(),
|
|
3330
3401
|
/** Number of providers in the latest run. */
|
|
3331
|
-
providerCount:
|
|
3402
|
+
providerCount: z28.number(),
|
|
3332
3403
|
/** GSC totals across the most-recent sync window. Null when GSC is not connected. */
|
|
3333
|
-
gsc:
|
|
3334
|
-
clicks:
|
|
3335
|
-
impressions:
|
|
3336
|
-
ctr:
|
|
3337
|
-
avgPosition:
|
|
3338
|
-
periodStart:
|
|
3339
|
-
periodEnd:
|
|
3404
|
+
gsc: z28.object({
|
|
3405
|
+
clicks: z28.number(),
|
|
3406
|
+
impressions: z28.number(),
|
|
3407
|
+
ctr: z28.number(),
|
|
3408
|
+
avgPosition: z28.number(),
|
|
3409
|
+
periodStart: z28.string(),
|
|
3410
|
+
periodEnd: z28.string()
|
|
3340
3411
|
}).nullable(),
|
|
3341
3412
|
/** GA4 totals across the most-recent sync period. Null when GA4 is not connected. */
|
|
3342
|
-
ga:
|
|
3343
|
-
sessions:
|
|
3344
|
-
users:
|
|
3345
|
-
periodStart:
|
|
3346
|
-
periodEnd:
|
|
3413
|
+
ga: z28.object({
|
|
3414
|
+
sessions: z28.number(),
|
|
3415
|
+
users: z28.number(),
|
|
3416
|
+
periodStart: z28.string(),
|
|
3417
|
+
periodEnd: z28.string()
|
|
3347
3418
|
}).nullable(),
|
|
3348
3419
|
/** Top 3-5 findings, each rendered as a single-sentence narrative. */
|
|
3349
|
-
findings:
|
|
3350
|
-
title:
|
|
3351
|
-
detail:
|
|
3352
|
-
tone:
|
|
3420
|
+
findings: z28.array(z28.object({
|
|
3421
|
+
title: z28.string(),
|
|
3422
|
+
detail: z28.string(),
|
|
3423
|
+
tone: z28.enum(["positive", "caution", "negative", "neutral"])
|
|
3353
3424
|
}))
|
|
3354
3425
|
});
|
|
3355
|
-
var citationCellSchema =
|
|
3356
|
-
citationState:
|
|
3357
|
-
answerMentioned:
|
|
3358
|
-
model:
|
|
3426
|
+
var citationCellSchema = z28.object({
|
|
3427
|
+
citationState: z28.enum(["cited", "not-cited", "pending"]),
|
|
3428
|
+
answerMentioned: z28.boolean().nullable(),
|
|
3429
|
+
model: z28.string().nullable()
|
|
3359
3430
|
});
|
|
3360
|
-
var citationScorecardSchema =
|
|
3361
|
-
queries:
|
|
3362
|
-
providers:
|
|
3431
|
+
var citationScorecardSchema = z28.object({
|
|
3432
|
+
queries: z28.array(z28.string()),
|
|
3433
|
+
providers: z28.array(z28.string()),
|
|
3363
3434
|
/** matrix[queryIndex][providerIndex] — null when no snapshot exists for the pair. */
|
|
3364
|
-
matrix:
|
|
3435
|
+
matrix: z28.array(z28.array(citationCellSchema.nullable())),
|
|
3365
3436
|
/** Per-provider citation rate (0..100). */
|
|
3366
|
-
providerRates:
|
|
3367
|
-
provider:
|
|
3368
|
-
citedCount:
|
|
3369
|
-
totalCount:
|
|
3370
|
-
citationRate:
|
|
3437
|
+
providerRates: z28.array(z28.object({
|
|
3438
|
+
provider: z28.string(),
|
|
3439
|
+
citedCount: z28.number(),
|
|
3440
|
+
totalCount: z28.number(),
|
|
3441
|
+
citationRate: z28.number()
|
|
3371
3442
|
}))
|
|
3372
3443
|
});
|
|
3373
|
-
var competitorRowSchema =
|
|
3374
|
-
domain:
|
|
3444
|
+
var competitorRowSchema = z28.object({
|
|
3445
|
+
domain: z28.string(),
|
|
3375
3446
|
/** Number of (query × provider) pairs that cited this competitor. */
|
|
3376
|
-
citationCount:
|
|
3447
|
+
citationCount: z28.number(),
|
|
3377
3448
|
/** Out-of count for the same denominator. */
|
|
3378
|
-
totalCount:
|
|
3449
|
+
totalCount: z28.number(),
|
|
3379
3450
|
/** 'High' | 'Moderate' | 'Low' | 'None' — from buildPortfolioProject pressure logic. */
|
|
3380
|
-
pressureLabel:
|
|
3451
|
+
pressureLabel: z28.enum(["High", "Moderate", "Low", "None"]),
|
|
3381
3452
|
/** Distinct queries on which this competitor was cited. */
|
|
3382
|
-
citedQueries:
|
|
3453
|
+
citedQueries: z28.array(z28.string()),
|
|
3383
3454
|
/**
|
|
3384
3455
|
* Citation share 0..100. Numerator = this competitor's `citationCount`.
|
|
3385
3456
|
* Denominator = sum of `citationCount` across all competitors plus the
|
|
@@ -3387,30 +3458,30 @@ var competitorRowSchema = z27.object({
|
|
|
3387
3458
|
* slots in the snapshot. Distinct from the project-level Mention Share
|
|
3388
3459
|
* gauge — that one is brand-in-answer-text, this one is domain-in-source-list.
|
|
3389
3460
|
*/
|
|
3390
|
-
sharePct:
|
|
3461
|
+
sharePct: z28.number(),
|
|
3391
3462
|
/**
|
|
3392
3463
|
* URLs from the latest run's grounding sources whose host matches this
|
|
3393
3464
|
* competitor's domain, with the queries each URL was cited for. Empty
|
|
3394
3465
|
* when no grounding-source data is available (e.g. no `rawResponse` JSON
|
|
3395
3466
|
* stored for the snapshots).
|
|
3396
3467
|
*/
|
|
3397
|
-
theirCitedPages:
|
|
3468
|
+
theirCitedPages: z28.array(z28.object({ url: z28.string(), citedFor: z28.array(z28.string()) }))
|
|
3398
3469
|
});
|
|
3399
|
-
var competitorLandscapeSchema =
|
|
3470
|
+
var competitorLandscapeSchema = z28.object({
|
|
3400
3471
|
/** Project's own citation count (for the bar chart comparing project vs competitors). */
|
|
3401
|
-
projectCitationCount:
|
|
3402
|
-
competitors:
|
|
3472
|
+
projectCitationCount: z28.number(),
|
|
3473
|
+
competitors: z28.array(competitorRowSchema)
|
|
3403
3474
|
});
|
|
3404
|
-
var mentionRowSchema =
|
|
3405
|
-
domain:
|
|
3475
|
+
var mentionRowSchema = z28.object({
|
|
3476
|
+
domain: z28.string(),
|
|
3406
3477
|
/** Number of (query × provider) pairs whose answer text mentioned this competitor's brand or domain. */
|
|
3407
|
-
mentionCount:
|
|
3478
|
+
mentionCount: z28.number(),
|
|
3408
3479
|
/** Out-of count for the same denominator (snapshots that had answer text). */
|
|
3409
|
-
totalCount:
|
|
3480
|
+
totalCount: z28.number(),
|
|
3410
3481
|
/** 'High' | 'Moderate' | 'Low' | 'None' — mention frequency tier (mirrors CompetitorRow.pressureLabel). */
|
|
3411
|
-
pressureLabel:
|
|
3482
|
+
pressureLabel: z28.enum(["High", "Moderate", "Low", "None"]),
|
|
3412
3483
|
/** Distinct queries on which this competitor was mentioned. */
|
|
3413
|
-
mentionedQueries:
|
|
3484
|
+
mentionedQueries: z28.array(z28.string()),
|
|
3414
3485
|
/**
|
|
3415
3486
|
* Mention share 0..100. Numerator = this competitor's `mentionCount`.
|
|
3416
3487
|
* Denominator = sum of `mentionCount` across all competitors plus the
|
|
@@ -3418,129 +3489,129 @@ var mentionRowSchema = z27.object({
|
|
|
3418
3489
|
* mention. Per-competitor split of the same head-to-head measure the
|
|
3419
3490
|
* project's hero `MentionShareDto` gauge headlines.
|
|
3420
3491
|
*/
|
|
3421
|
-
sharePct:
|
|
3492
|
+
sharePct: z28.number()
|
|
3422
3493
|
});
|
|
3423
|
-
var mentionLandscapeSchema =
|
|
3494
|
+
var mentionLandscapeSchema = z28.object({
|
|
3424
3495
|
/** Project's own mention count (for the bar chart comparing project vs competitors). */
|
|
3425
|
-
projectMentionCount:
|
|
3496
|
+
projectMentionCount: z28.number(),
|
|
3426
3497
|
/** Snapshots considered — those with non-empty answerText. Drives the totalCount denominator. */
|
|
3427
|
-
totalAnswerSnapshots:
|
|
3428
|
-
competitors:
|
|
3498
|
+
totalAnswerSnapshots: z28.number(),
|
|
3499
|
+
competitors: z28.array(mentionRowSchema)
|
|
3429
3500
|
});
|
|
3430
|
-
var aiSourceCategoryBucketSchema =
|
|
3501
|
+
var aiSourceCategoryBucketSchema = z28.object({
|
|
3431
3502
|
/** Category slug from packages/contracts/src/source-categories. */
|
|
3432
|
-
category:
|
|
3503
|
+
category: z28.string(),
|
|
3433
3504
|
/** Display label. */
|
|
3434
|
-
label:
|
|
3505
|
+
label: z28.string(),
|
|
3435
3506
|
/** Number of citations falling in this category. */
|
|
3436
|
-
count:
|
|
3507
|
+
count: z28.number(),
|
|
3437
3508
|
/** 0..100 share of total citations. */
|
|
3438
|
-
sharePct:
|
|
3509
|
+
sharePct: z28.number()
|
|
3439
3510
|
});
|
|
3440
|
-
var aiSourceOriginSchema =
|
|
3441
|
-
categories:
|
|
3511
|
+
var aiSourceOriginSchema = z28.object({
|
|
3512
|
+
categories: z28.array(aiSourceCategoryBucketSchema),
|
|
3442
3513
|
/** Top 20 source domains by citation count (excluding the project's own domain). */
|
|
3443
|
-
topDomains:
|
|
3444
|
-
domain:
|
|
3445
|
-
count:
|
|
3514
|
+
topDomains: z28.array(z28.object({
|
|
3515
|
+
domain: z28.string(),
|
|
3516
|
+
count: z28.number(),
|
|
3446
3517
|
/** True when the domain is one of the project's tracked competitors. */
|
|
3447
|
-
isCompetitor:
|
|
3518
|
+
isCompetitor: z28.boolean()
|
|
3448
3519
|
}))
|
|
3449
3520
|
});
|
|
3450
|
-
var gscQueryRowSchema =
|
|
3451
|
-
query:
|
|
3452
|
-
clicks:
|
|
3453
|
-
impressions:
|
|
3454
|
-
ctr:
|
|
3455
|
-
avgPosition:
|
|
3521
|
+
var gscQueryRowSchema = z28.object({
|
|
3522
|
+
query: z28.string(),
|
|
3523
|
+
clicks: z28.number(),
|
|
3524
|
+
impressions: z28.number(),
|
|
3525
|
+
ctr: z28.number(),
|
|
3526
|
+
avgPosition: z28.number(),
|
|
3456
3527
|
/** Heuristic categorization: 'brand' | 'lead-gen' | 'industry' | 'other'. */
|
|
3457
|
-
category:
|
|
3458
|
-
});
|
|
3459
|
-
var gscSectionSchema =
|
|
3460
|
-
periodStart:
|
|
3461
|
-
periodEnd:
|
|
3462
|
-
totalClicks:
|
|
3463
|
-
totalImpressions:
|
|
3464
|
-
ctr:
|
|
3465
|
-
avgPosition:
|
|
3466
|
-
topQueries:
|
|
3467
|
-
categoryBreakdown:
|
|
3468
|
-
category:
|
|
3469
|
-
clicks:
|
|
3470
|
-
impressions:
|
|
3471
|
-
sharePct:
|
|
3528
|
+
category: z28.enum(["brand", "lead-gen", "industry", "other"])
|
|
3529
|
+
});
|
|
3530
|
+
var gscSectionSchema = z28.object({
|
|
3531
|
+
periodStart: z28.string(),
|
|
3532
|
+
periodEnd: z28.string(),
|
|
3533
|
+
totalClicks: z28.number(),
|
|
3534
|
+
totalImpressions: z28.number(),
|
|
3535
|
+
ctr: z28.number(),
|
|
3536
|
+
avgPosition: z28.number(),
|
|
3537
|
+
topQueries: z28.array(gscQueryRowSchema),
|
|
3538
|
+
categoryBreakdown: z28.array(z28.object({
|
|
3539
|
+
category: z28.enum(["brand", "lead-gen", "industry", "other"]),
|
|
3540
|
+
clicks: z28.number(),
|
|
3541
|
+
impressions: z28.number(),
|
|
3542
|
+
sharePct: z28.number()
|
|
3472
3543
|
})),
|
|
3473
|
-
trend:
|
|
3544
|
+
trend: z28.array(z28.object({ date: z28.string(), clicks: z28.number(), impressions: z28.number() })),
|
|
3474
3545
|
/**
|
|
3475
3546
|
* Tracked AEO queries that have no GSC impressions in the report window.
|
|
3476
3547
|
* Surfaces queries that may not represent real search demand.
|
|
3477
3548
|
*/
|
|
3478
|
-
trackedButNoGsc:
|
|
3549
|
+
trackedButNoGsc: z28.array(z28.string()),
|
|
3479
3550
|
/**
|
|
3480
3551
|
* GSC top queries (sorted by impressions desc) that are not tracked as
|
|
3481
3552
|
* AEO queries — the candidate set for adding to the AEO project.
|
|
3482
3553
|
*/
|
|
3483
|
-
gscButNotTracked:
|
|
3484
|
-
});
|
|
3485
|
-
var gaTrafficSectionSchema =
|
|
3486
|
-
totalSessions:
|
|
3487
|
-
totalUsers:
|
|
3488
|
-
totalOrganicSessions:
|
|
3489
|
-
periodStart:
|
|
3490
|
-
periodEnd:
|
|
3491
|
-
topLandingPages:
|
|
3492
|
-
page:
|
|
3493
|
-
sessions:
|
|
3494
|
-
users:
|
|
3495
|
-
organicSessions:
|
|
3554
|
+
gscButNotTracked: z28.array(z28.string())
|
|
3555
|
+
});
|
|
3556
|
+
var gaTrafficSectionSchema = z28.object({
|
|
3557
|
+
totalSessions: z28.number(),
|
|
3558
|
+
totalUsers: z28.number(),
|
|
3559
|
+
totalOrganicSessions: z28.number(),
|
|
3560
|
+
periodStart: z28.string(),
|
|
3561
|
+
periodEnd: z28.string(),
|
|
3562
|
+
topLandingPages: z28.array(z28.object({
|
|
3563
|
+
page: z28.string(),
|
|
3564
|
+
sessions: z28.number(),
|
|
3565
|
+
users: z28.number(),
|
|
3566
|
+
organicSessions: z28.number()
|
|
3496
3567
|
})),
|
|
3497
|
-
channelBreakdown:
|
|
3498
|
-
channel:
|
|
3499
|
-
sessions:
|
|
3500
|
-
sharePct:
|
|
3568
|
+
channelBreakdown: z28.array(z28.object({
|
|
3569
|
+
channel: z28.string(),
|
|
3570
|
+
sessions: z28.number(),
|
|
3571
|
+
sharePct: z28.number()
|
|
3501
3572
|
}))
|
|
3502
3573
|
});
|
|
3503
|
-
var socialReferralSectionSchema =
|
|
3504
|
-
totalSessions:
|
|
3505
|
-
organicSessions:
|
|
3506
|
-
paidSessions:
|
|
3507
|
-
channels:
|
|
3508
|
-
channelGroup:
|
|
3509
|
-
sessions:
|
|
3510
|
-
sharePct:
|
|
3574
|
+
var socialReferralSectionSchema = z28.object({
|
|
3575
|
+
totalSessions: z28.number(),
|
|
3576
|
+
organicSessions: z28.number(),
|
|
3577
|
+
paidSessions: z28.number(),
|
|
3578
|
+
channels: z28.array(z28.object({
|
|
3579
|
+
channelGroup: z28.string(),
|
|
3580
|
+
sessions: z28.number(),
|
|
3581
|
+
sharePct: z28.number()
|
|
3511
3582
|
})),
|
|
3512
|
-
topCampaigns:
|
|
3513
|
-
source:
|
|
3514
|
-
medium:
|
|
3515
|
-
sessions:
|
|
3583
|
+
topCampaigns: z28.array(z28.object({
|
|
3584
|
+
source: z28.string(),
|
|
3585
|
+
medium: z28.string(),
|
|
3586
|
+
sessions: z28.number()
|
|
3516
3587
|
}))
|
|
3517
3588
|
});
|
|
3518
|
-
var aiReferralSectionSchema =
|
|
3519
|
-
totalSessions:
|
|
3520
|
-
totalUsers:
|
|
3521
|
-
bySource:
|
|
3522
|
-
source:
|
|
3523
|
-
sessions:
|
|
3524
|
-
users:
|
|
3525
|
-
sharePct:
|
|
3589
|
+
var aiReferralSectionSchema = z28.object({
|
|
3590
|
+
totalSessions: z28.number(),
|
|
3591
|
+
totalUsers: z28.number(),
|
|
3592
|
+
bySource: z28.array(z28.object({
|
|
3593
|
+
source: z28.string(),
|
|
3594
|
+
sessions: z28.number(),
|
|
3595
|
+
users: z28.number(),
|
|
3596
|
+
sharePct: z28.number()
|
|
3526
3597
|
})),
|
|
3527
|
-
trend:
|
|
3528
|
-
topLandingPages:
|
|
3529
|
-
page:
|
|
3530
|
-
sessions:
|
|
3531
|
-
users:
|
|
3598
|
+
trend: z28.array(z28.object({ date: z28.string(), sessions: z28.number() })),
|
|
3599
|
+
topLandingPages: z28.array(z28.object({
|
|
3600
|
+
page: z28.string(),
|
|
3601
|
+
sessions: z28.number(),
|
|
3602
|
+
users: z28.number()
|
|
3532
3603
|
}))
|
|
3533
3604
|
});
|
|
3534
|
-
var serverActivitySectionSchema =
|
|
3605
|
+
var serverActivitySectionSchema = z28.object({
|
|
3535
3606
|
/** ISO8601 inclusive lower bound of the report window (default: 7 days). */
|
|
3536
|
-
windowStart:
|
|
3607
|
+
windowStart: z28.string(),
|
|
3537
3608
|
/** ISO8601 inclusive upper bound. */
|
|
3538
|
-
windowEnd:
|
|
3539
|
-
hasData:
|
|
3609
|
+
windowEnd: z28.string(),
|
|
3610
|
+
hasData: z28.boolean(),
|
|
3540
3611
|
/** Last-7d total verified crawler hits, with prior 7d for delta. */
|
|
3541
|
-
verifiedCrawlerHits:
|
|
3612
|
+
verifiedCrawlerHits: z28.object({ current: z28.number(), prior: z28.number(), deltaPct: z28.number().nullable() }),
|
|
3542
3613
|
/** Last-7d total unverified crawler hits, separated from verified trust metrics. */
|
|
3543
|
-
unverifiedCrawlerHits:
|
|
3614
|
+
unverifiedCrawlerHits: z28.object({ current: z28.number(), prior: z28.number(), deltaPct: z28.number().nullable() }),
|
|
3544
3615
|
/**
|
|
3545
3616
|
* Last-7d on-demand per-user fetches from AI surfaces (ChatGPT-User,
|
|
3546
3617
|
* Perplexity-User, MistralAI-User). Disjoint from `verifiedCrawlerHits` /
|
|
@@ -3549,19 +3620,19 @@ var serverActivitySectionSchema = z27.object({
|
|
|
3549
3620
|
* because the operational question for user-fetch is "is this happening?"
|
|
3550
3621
|
* not "is this a confirmed bot identity?"
|
|
3551
3622
|
*/
|
|
3552
|
-
aiUserFetchHits:
|
|
3623
|
+
aiUserFetchHits: z28.object({ current: z28.number(), prior: z28.number(), deltaPct: z28.number().nullable() }),
|
|
3553
3624
|
/** Last-7d AI-referral sessions (sessionized from server-side request evidence). */
|
|
3554
|
-
referralArrivals:
|
|
3625
|
+
referralArrivals: z28.object({ current: z28.number(), prior: z28.number(), deltaPct: z28.number().nullable() }),
|
|
3555
3626
|
/** Per-AI-operator breakdown (OpenAI, Anthropic, Google AI, Perplexity, …). */
|
|
3556
|
-
byOperator:
|
|
3557
|
-
operator:
|
|
3558
|
-
verifiedHits:
|
|
3627
|
+
byOperator: z28.array(z28.object({
|
|
3628
|
+
operator: z28.string(),
|
|
3629
|
+
verifiedHits: z28.number(),
|
|
3559
3630
|
/** Shown to agency audience only: claimed-bot UA, source IP not in a published range. */
|
|
3560
|
-
unverifiedHits:
|
|
3631
|
+
unverifiedHits: z28.number(),
|
|
3561
3632
|
/** Per-user fetches from this operator's AI surface (ChatGPT-User, …). */
|
|
3562
|
-
userFetchHits:
|
|
3563
|
-
referralArrivals:
|
|
3564
|
-
deltaPct:
|
|
3633
|
+
userFetchHits: z28.number(),
|
|
3634
|
+
referralArrivals: z28.number(),
|
|
3635
|
+
deltaPct: z28.number().nullable()
|
|
3565
3636
|
})),
|
|
3566
3637
|
/**
|
|
3567
3638
|
* Top crawled paths (verified only, last-7d). Path-level citation cross-reference
|
|
@@ -3571,84 +3642,84 @@ var serverActivitySectionSchema = z27.object({
|
|
|
3571
3642
|
* citation evidence can extend this entry with a `citationState` field without
|
|
3572
3643
|
* breaking the contract.
|
|
3573
3644
|
*/
|
|
3574
|
-
topCrawledPaths:
|
|
3575
|
-
path:
|
|
3576
|
-
verifiedHits:
|
|
3645
|
+
topCrawledPaths: z28.array(z28.object({
|
|
3646
|
+
path: z28.string(),
|
|
3647
|
+
verifiedHits: z28.number(),
|
|
3577
3648
|
/** How many distinct AI operators crawled this path in the window. */
|
|
3578
|
-
distinctOperators:
|
|
3649
|
+
distinctOperators: z28.number()
|
|
3579
3650
|
})),
|
|
3580
3651
|
/** AI products that sent ≥1 session in the window (referral by destination). */
|
|
3581
|
-
referralProducts:
|
|
3582
|
-
product:
|
|
3583
|
-
arrivals:
|
|
3584
|
-
distinctLandingPaths:
|
|
3652
|
+
referralProducts: z28.array(z28.object({
|
|
3653
|
+
product: z28.string(),
|
|
3654
|
+
arrivals: z28.number(),
|
|
3655
|
+
distinctLandingPaths: z28.number()
|
|
3585
3656
|
})),
|
|
3586
3657
|
/** Daily trend, last 14d for sparkline / chart rendering. */
|
|
3587
|
-
dailyTrend:
|
|
3588
|
-
date:
|
|
3589
|
-
verifiedCrawlerHits:
|
|
3590
|
-
userFetchHits:
|
|
3591
|
-
referralArrivals:
|
|
3658
|
+
dailyTrend: z28.array(z28.object({
|
|
3659
|
+
date: z28.string(),
|
|
3660
|
+
verifiedCrawlerHits: z28.number(),
|
|
3661
|
+
userFetchHits: z28.number(),
|
|
3662
|
+
referralArrivals: z28.number()
|
|
3592
3663
|
})),
|
|
3593
3664
|
/**
|
|
3594
3665
|
* Top landing paths for AI-referral sessions (last-7d).
|
|
3595
3666
|
* Complements `topCrawledPaths` (what bots fetch) with what humans actually land on.
|
|
3596
3667
|
*/
|
|
3597
|
-
topReferralLandingPaths:
|
|
3598
|
-
path:
|
|
3599
|
-
arrivals:
|
|
3600
|
-
distinctProducts:
|
|
3668
|
+
topReferralLandingPaths: z28.array(z28.object({
|
|
3669
|
+
path: z28.string(),
|
|
3670
|
+
arrivals: z28.number(),
|
|
3671
|
+
distinctProducts: z28.number()
|
|
3601
3672
|
}))
|
|
3602
3673
|
});
|
|
3603
|
-
var indexingHealthSectionSchema =
|
|
3674
|
+
var indexingHealthSectionSchema = z28.object({
|
|
3604
3675
|
/** Source: 'google' | 'bing' | null when neither is connected. */
|
|
3605
|
-
provider:
|
|
3606
|
-
total:
|
|
3607
|
-
indexed:
|
|
3608
|
-
notIndexed:
|
|
3676
|
+
provider: z28.enum(["google", "bing"]).nullable(),
|
|
3677
|
+
total: z28.number(),
|
|
3678
|
+
indexed: z28.number(),
|
|
3679
|
+
notIndexed: z28.number(),
|
|
3609
3680
|
/** Google-only — pages explicitly marked as deindexed. Bing reports 'unknown' instead. */
|
|
3610
|
-
deindexed:
|
|
3681
|
+
deindexed: z28.number(),
|
|
3611
3682
|
/** Bing-only — pages with no inspection data yet. */
|
|
3612
|
-
unknown:
|
|
3683
|
+
unknown: z28.number(),
|
|
3613
3684
|
/** 0..100. */
|
|
3614
|
-
indexedPct:
|
|
3685
|
+
indexedPct: z28.number()
|
|
3615
3686
|
});
|
|
3616
|
-
var citationsTrendPointSchema =
|
|
3687
|
+
var citationsTrendPointSchema = z28.object({
|
|
3617
3688
|
/** Run ID — anchor for cross-section linking. */
|
|
3618
|
-
runId:
|
|
3689
|
+
runId: z28.string(),
|
|
3619
3690
|
/** ISO timestamp when the run finished (or createdAt fallback). */
|
|
3620
|
-
date:
|
|
3691
|
+
date: z28.string(),
|
|
3621
3692
|
/**
|
|
3622
3693
|
* 0..100 — same per-query unique-cited definition as
|
|
3623
3694
|
* `ReportExecutiveSummary.citationRate`. Stable across runs with different
|
|
3624
3695
|
* provider counts so the trend line measures real movement rather than
|
|
3625
3696
|
* provider-count variance.
|
|
3626
3697
|
*/
|
|
3627
|
-
citationRate:
|
|
3698
|
+
citationRate: z28.number(),
|
|
3628
3699
|
/** Numerator of `citationRate` for this run. */
|
|
3629
|
-
citedQueryCount:
|
|
3700
|
+
citedQueryCount: z28.number(),
|
|
3630
3701
|
/** Denominator of `citationRate` for this run. */
|
|
3631
|
-
totalQueryCount:
|
|
3702
|
+
totalQueryCount: z28.number(),
|
|
3632
3703
|
/** 0..100 — same per-query unique-mentioned definition as `ReportExecutiveSummary.mentionRate`. */
|
|
3633
|
-
mentionRate:
|
|
3704
|
+
mentionRate: z28.number(),
|
|
3634
3705
|
/** Numerator of `mentionRate` for this run. */
|
|
3635
|
-
mentionedQueryCount:
|
|
3706
|
+
mentionedQueryCount: z28.number(),
|
|
3636
3707
|
/**
|
|
3637
3708
|
* Per-provider rates for the same run. Each provider's rate is per-pair
|
|
3638
3709
|
* within that provider (`cited / scanned`), so it remains comparable
|
|
3639
3710
|
* between providers in the same run.
|
|
3640
3711
|
*/
|
|
3641
|
-
providerRates:
|
|
3642
|
-
});
|
|
3643
|
-
var reportInsightSchema =
|
|
3644
|
-
id:
|
|
3645
|
-
type:
|
|
3646
|
-
severity:
|
|
3647
|
-
title:
|
|
3648
|
-
query:
|
|
3649
|
-
provider:
|
|
3650
|
-
recommendation:
|
|
3651
|
-
createdAt:
|
|
3712
|
+
providerRates: z28.array(z28.object({ provider: z28.string(), citationRate: z28.number() }))
|
|
3713
|
+
});
|
|
3714
|
+
var reportInsightSchema = z28.object({
|
|
3715
|
+
id: z28.string(),
|
|
3716
|
+
type: z28.enum(["regression", "gain", "opportunity"]),
|
|
3717
|
+
severity: z28.enum(["critical", "high", "medium", "low"]),
|
|
3718
|
+
title: z28.string(),
|
|
3719
|
+
query: z28.string(),
|
|
3720
|
+
provider: z28.string(),
|
|
3721
|
+
recommendation: z28.string().nullable(),
|
|
3722
|
+
createdAt: z28.string(),
|
|
3652
3723
|
/**
|
|
3653
3724
|
* How many times this insight fired across recent runs for the same
|
|
3654
3725
|
* `(query, provider, type)` tuple. Always ≥ 1. Insights returned by the
|
|
@@ -3656,57 +3727,57 @@ var reportInsightSchema = z27.object({
|
|
|
3656
3727
|
* surfacing the multiplicity. Use it directly instead of grouping again
|
|
3657
3728
|
* client-side — counts derived from raw insight rows will overcount.
|
|
3658
3729
|
*/
|
|
3659
|
-
instanceCount:
|
|
3730
|
+
instanceCount: z28.number()
|
|
3660
3731
|
});
|
|
3661
|
-
var recommendedNextStepSchema =
|
|
3732
|
+
var recommendedNextStepSchema = z28.object({
|
|
3662
3733
|
/** 'immediate' | 'short-term' | 'medium-term' — bucketed by severity heuristic. */
|
|
3663
|
-
horizon:
|
|
3664
|
-
title:
|
|
3665
|
-
rationale:
|
|
3734
|
+
horizon: z28.enum(["immediate", "short-term", "medium-term"]),
|
|
3735
|
+
title: z28.string(),
|
|
3736
|
+
rationale: z28.string()
|
|
3666
3737
|
});
|
|
3667
|
-
var reportRateDeltaSchema =
|
|
3738
|
+
var reportRateDeltaSchema = z28.object({
|
|
3668
3739
|
/** Current value (0..100 for rates, raw count otherwise). When `window`
|
|
3669
3740
|
* is present this is the average over the last `window` checks. */
|
|
3670
|
-
current:
|
|
3741
|
+
current: z28.number(),
|
|
3671
3742
|
/** Prior value compared against. When `window` is present this is the
|
|
3672
3743
|
* average over the prior `window` checks before that. */
|
|
3673
|
-
prior:
|
|
3744
|
+
prior: z28.number(),
|
|
3674
3745
|
/** Absolute delta (current − prior). Negative = decrease. */
|
|
3675
|
-
deltaAbs:
|
|
3746
|
+
deltaAbs: z28.number(),
|
|
3676
3747
|
/**
|
|
3677
3748
|
* Direction tag for tone mapping. Threshold is metric-specific (3pp for
|
|
3678
3749
|
* rates, 0.5 for counts) so small noise lands as 'flat' rather than
|
|
3679
3750
|
* flipping up/down each run.
|
|
3680
3751
|
*/
|
|
3681
|
-
direction:
|
|
3752
|
+
direction: z28.enum(["up", "down", "flat"]),
|
|
3682
3753
|
/**
|
|
3683
3754
|
* How many points went into each side of the average. Omitted (or 1)
|
|
3684
3755
|
* means point-to-point (legacy "since last check"). Higher values mean
|
|
3685
3756
|
* a rolling-average comparison — renderers should label it as
|
|
3686
3757
|
* "vs prior N checks" when this is ≥ 2.
|
|
3687
3758
|
*/
|
|
3688
|
-
window:
|
|
3759
|
+
window: z28.number().optional()
|
|
3689
3760
|
});
|
|
3690
|
-
var reportProviderMovementSchema =
|
|
3691
|
-
provider:
|
|
3692
|
-
current:
|
|
3693
|
-
prior:
|
|
3694
|
-
deltaAbs:
|
|
3695
|
-
direction:
|
|
3761
|
+
var reportProviderMovementSchema = z28.object({
|
|
3762
|
+
provider: z28.string(),
|
|
3763
|
+
current: z28.number(),
|
|
3764
|
+
prior: z28.number(),
|
|
3765
|
+
deltaAbs: z28.number(),
|
|
3766
|
+
direction: z28.enum(["up", "down", "flat"])
|
|
3696
3767
|
});
|
|
3697
|
-
var whatsChangedSectionSchema =
|
|
3768
|
+
var whatsChangedSectionSchema = z28.object({
|
|
3698
3769
|
/**
|
|
3699
3770
|
* False when there's no prior run (or fewer than the trend baseline),
|
|
3700
3771
|
* meaning all per-metric deltas will be null. Renderers use this to swap
|
|
3701
3772
|
* in a "establishing baseline" fallback rather than rendering empty
|
|
3702
3773
|
* delta tiles.
|
|
3703
3774
|
*/
|
|
3704
|
-
enoughHistory:
|
|
3775
|
+
enoughHistory: z28.boolean(),
|
|
3705
3776
|
/**
|
|
3706
3777
|
* One-sentence narrative summary suitable as a section subtitle.
|
|
3707
3778
|
* Always present — even on baseline, narrates whatever signal exists.
|
|
3708
3779
|
*/
|
|
3709
|
-
headline:
|
|
3780
|
+
headline: z28.string(),
|
|
3710
3781
|
/** Citation rate delta vs the prior completed run. Null when no prior run. */
|
|
3711
3782
|
citationRate: reportRateDeltaSchema.nullable(),
|
|
3712
3783
|
/** Mention rate delta vs the prior completed run. Null when no prior run. */
|
|
@@ -3729,24 +3800,24 @@ var whatsChangedSectionSchema = z27.object({
|
|
|
3729
3800
|
* when no prior run. Sorted by |deltaAbs| desc — providers with the
|
|
3730
3801
|
* biggest swing first.
|
|
3731
3802
|
*/
|
|
3732
|
-
providerMovements:
|
|
3803
|
+
providerMovements: z28.array(reportProviderMovementSchema),
|
|
3733
3804
|
/**
|
|
3734
3805
|
* Top wins this period — gains surfaced by the intelligence engine.
|
|
3735
3806
|
* Capped at 5; sourced from `insights` filtered to `type: 'gain'`.
|
|
3736
3807
|
*/
|
|
3737
|
-
wins:
|
|
3808
|
+
wins: z28.array(reportInsightSchema),
|
|
3738
3809
|
/**
|
|
3739
3810
|
* Top regressions this period — citations or mentions lost. Capped at 5;
|
|
3740
3811
|
* sourced from `insights` filtered to `type: 'regression'`.
|
|
3741
3812
|
*/
|
|
3742
|
-
regressions:
|
|
3743
|
-
});
|
|
3744
|
-
var reportAudienceSchema =
|
|
3745
|
-
var reportActionAudienceSchema =
|
|
3746
|
-
var reportActionHorizonSchema =
|
|
3747
|
-
var reportActionConfidenceSchema =
|
|
3748
|
-
var reportToneSchema =
|
|
3749
|
-
var reportActionCategorySchema =
|
|
3813
|
+
regressions: z28.array(reportInsightSchema)
|
|
3814
|
+
});
|
|
3815
|
+
var reportAudienceSchema = z28.enum(["agency", "client"]);
|
|
3816
|
+
var reportActionAudienceSchema = z28.enum(["agency", "client", "both"]);
|
|
3817
|
+
var reportActionHorizonSchema = z28.enum(["immediate", "short-term", "medium-term"]);
|
|
3818
|
+
var reportActionConfidenceSchema = z28.enum(["high", "medium", "low"]);
|
|
3819
|
+
var reportToneSchema = z28.enum(["positive", "caution", "negative", "neutral"]);
|
|
3820
|
+
var reportActionCategorySchema = z28.enum([
|
|
3750
3821
|
"content",
|
|
3751
3822
|
"competitors",
|
|
3752
3823
|
"provider",
|
|
@@ -3755,23 +3826,23 @@ var reportActionCategorySchema = z27.enum([
|
|
|
3755
3826
|
"location",
|
|
3756
3827
|
"monitoring"
|
|
3757
3828
|
]);
|
|
3758
|
-
var reportActionPlanItemSchema =
|
|
3829
|
+
var reportActionPlanItemSchema = z28.object({
|
|
3759
3830
|
/** Which report audience should see this action. `both` renders in both modes. */
|
|
3760
3831
|
audience: reportActionAudienceSchema,
|
|
3761
3832
|
/** Stable sort priority. Lower numbers render earlier. */
|
|
3762
|
-
priority:
|
|
3833
|
+
priority: z28.number(),
|
|
3763
3834
|
/** When this should be tackled. */
|
|
3764
3835
|
horizon: reportActionHorizonSchema,
|
|
3765
3836
|
category: reportActionCategorySchema,
|
|
3766
|
-
title:
|
|
3837
|
+
title: z28.string(),
|
|
3767
3838
|
/** Direct next step written as an operator/client-friendly imperative. */
|
|
3768
|
-
action:
|
|
3839
|
+
action: z28.string(),
|
|
3769
3840
|
/** Why this matters. Keep each entry concise and evidence-backed. */
|
|
3770
|
-
why:
|
|
3841
|
+
why: z28.array(z28.string()),
|
|
3771
3842
|
/** Specific observations that justify the action. */
|
|
3772
|
-
evidence:
|
|
3843
|
+
evidence: z28.array(z28.string()),
|
|
3773
3844
|
/** What should move if the action worked. */
|
|
3774
|
-
successMetric:
|
|
3845
|
+
successMetric: z28.string(),
|
|
3775
3846
|
/** Confidence in the recommendation based on the available evidence. */
|
|
3776
3847
|
confidence: reportActionConfidenceSchema,
|
|
3777
3848
|
/**
|
|
@@ -3783,23 +3854,23 @@ var reportActionPlanItemSchema = z27.object({
|
|
|
3783
3854
|
* load. Actions sourced from other signals (competitor gaps, indexing
|
|
3784
3855
|
* issues, etc.) omit this and use their own dismiss flows.
|
|
3785
3856
|
*/
|
|
3786
|
-
targetRef:
|
|
3857
|
+
targetRef: z28.string().optional()
|
|
3787
3858
|
});
|
|
3788
|
-
var reportClientSummarySchema =
|
|
3789
|
-
headline:
|
|
3790
|
-
overview:
|
|
3791
|
-
actionItems:
|
|
3792
|
-
confidenceNotes:
|
|
3859
|
+
var reportClientSummarySchema = z28.object({
|
|
3860
|
+
headline: z28.string(),
|
|
3861
|
+
overview: z28.string(),
|
|
3862
|
+
actionItems: z28.array(reportActionPlanItemSchema),
|
|
3863
|
+
confidenceNotes: z28.array(z28.string())
|
|
3793
3864
|
});
|
|
3794
|
-
var reportAgencyDiagnosticSchema =
|
|
3795
|
-
title:
|
|
3796
|
-
detail:
|
|
3797
|
-
severity:
|
|
3798
|
-
evidence:
|
|
3865
|
+
var reportAgencyDiagnosticSchema = z28.object({
|
|
3866
|
+
title: z28.string(),
|
|
3867
|
+
detail: z28.string(),
|
|
3868
|
+
severity: z28.enum(["positive", "caution", "negative", "neutral"]),
|
|
3869
|
+
evidence: z28.array(z28.string())
|
|
3799
3870
|
});
|
|
3800
|
-
var reportAgencyDiagnosticsSchema =
|
|
3801
|
-
priorities:
|
|
3802
|
-
diagnostics:
|
|
3871
|
+
var reportAgencyDiagnosticsSchema = z28.object({
|
|
3872
|
+
priorities: z28.array(reportActionPlanItemSchema),
|
|
3873
|
+
diagnostics: z28.array(reportAgencyDiagnosticSchema)
|
|
3803
3874
|
});
|
|
3804
3875
|
function reportActionTone(action) {
|
|
3805
3876
|
if (action.horizon === "immediate") return "negative";
|
|
@@ -3857,7 +3928,7 @@ function reportConfidenceLabel(confidence) {
|
|
|
3857
3928
|
return "Low";
|
|
3858
3929
|
}
|
|
3859
3930
|
}
|
|
3860
|
-
var projectReportDtoSchema =
|
|
3931
|
+
var projectReportDtoSchema = z28.object({
|
|
3861
3932
|
meta: reportMetaSchema,
|
|
3862
3933
|
executiveSummary: reportExecutiveSummarySchema,
|
|
3863
3934
|
citationScorecard: citationScorecardSchema,
|
|
@@ -3871,16 +3942,16 @@ var projectReportDtoSchema = z27.object({
|
|
|
3871
3942
|
/** Server-side log-evidence visibility (crawls + click-through sessions). Null when no traffic source connected. */
|
|
3872
3943
|
serverActivity: serverActivitySectionSchema.nullable(),
|
|
3873
3944
|
indexingHealth: indexingHealthSectionSchema.nullable(),
|
|
3874
|
-
citationsTrend:
|
|
3945
|
+
citationsTrend: z28.array(citationsTrendPointSchema),
|
|
3875
3946
|
/**
|
|
3876
3947
|
* Trend-focused "what's changed" summary for the report's act 2. Always
|
|
3877
3948
|
* present; renderers gate empty/baseline states via `enoughHistory`.
|
|
3878
3949
|
*/
|
|
3879
3950
|
whatsChanged: whatsChangedSectionSchema,
|
|
3880
|
-
insights:
|
|
3881
|
-
recommendedNextSteps:
|
|
3951
|
+
insights: z28.array(reportInsightSchema),
|
|
3952
|
+
recommendedNextSteps: z28.array(recommendedNextStepSchema),
|
|
3882
3953
|
/** Canonical structured actions shared by the client and agency render modes. */
|
|
3883
|
-
actionPlan:
|
|
3954
|
+
actionPlan: z28.array(reportActionPlanItemSchema),
|
|
3884
3955
|
/** Polished client-facing summary and action shortlist. */
|
|
3885
3956
|
clientSummary: reportClientSummarySchema,
|
|
3886
3957
|
/** Technical, evidence-oriented operator diagnostics for agency mode. */
|
|
@@ -3890,17 +3961,17 @@ var projectReportDtoSchema = z27.object({
|
|
|
3890
3961
|
* intelligence layer (`buildContentTargetRows`). Empty when no run has
|
|
3891
3962
|
* produced candidate queries with demand or competitor signal.
|
|
3892
3963
|
*/
|
|
3893
|
-
contentOpportunities:
|
|
3964
|
+
contentOpportunities: z28.array(contentTargetRowDtoSchema),
|
|
3894
3965
|
/**
|
|
3895
3966
|
* Queries where competitors were cited but the project was not. Sourced
|
|
3896
3967
|
* from `buildContentGapRows`. Empty until the first answer-visibility run.
|
|
3897
3968
|
*/
|
|
3898
|
-
contentGaps:
|
|
3969
|
+
contentGaps: z28.array(contentGapRowDtoSchema),
|
|
3899
3970
|
/**
|
|
3900
3971
|
* Per-query grounding source map (own + competitor cited URLs). Sourced
|
|
3901
3972
|
* from `buildContentSourceRows`. Empty until the first answer-visibility run.
|
|
3902
3973
|
*/
|
|
3903
|
-
groundingSources:
|
|
3974
|
+
groundingSources: z28.array(contentSourceRowDtoSchema)
|
|
3904
3975
|
});
|
|
3905
3976
|
|
|
3906
3977
|
// ../contracts/src/report-dedup.ts
|
|
@@ -3971,10 +4042,10 @@ function dedupeReportOpportunities(report) {
|
|
|
3971
4042
|
}
|
|
3972
4043
|
|
|
3973
4044
|
// ../contracts/src/skills.ts
|
|
3974
|
-
import { z as
|
|
3975
|
-
var codingAgentSchema =
|
|
4045
|
+
import { z as z29 } from "zod";
|
|
4046
|
+
var codingAgentSchema = z29.enum(["claude", "codex"]);
|
|
3976
4047
|
var CodingAgents = codingAgentSchema.enum;
|
|
3977
|
-
var skillsClientSchema =
|
|
4048
|
+
var skillsClientSchema = z29.enum(["claude", "codex", "all"]);
|
|
3978
4049
|
var SkillsClients = skillsClientSchema.enum;
|
|
3979
4050
|
var SKILL_MANIFEST_FILENAME = ".canonry-skill-manifest.json";
|
|
3980
4051
|
function classifySkillFile(params) {
|
|
@@ -3992,8 +4063,8 @@ function coerceSkillManifest(parsed) {
|
|
|
3992
4063
|
}
|
|
3993
4064
|
|
|
3994
4065
|
// ../contracts/src/traffic.ts
|
|
3995
|
-
import { z as
|
|
3996
|
-
var trafficSourceTypeSchema =
|
|
4066
|
+
import { z as z30 } from "zod";
|
|
4067
|
+
var trafficSourceTypeSchema = z30.enum([
|
|
3997
4068
|
"cloud-run",
|
|
3998
4069
|
"wordpress",
|
|
3999
4070
|
"cloudflare",
|
|
@@ -4001,7 +4072,7 @@ var trafficSourceTypeSchema = z29.enum([
|
|
|
4001
4072
|
"generic-log"
|
|
4002
4073
|
]);
|
|
4003
4074
|
var TrafficSourceTypes = trafficSourceTypeSchema.enum;
|
|
4004
|
-
var trafficAdapterCapabilitySchema =
|
|
4075
|
+
var trafficAdapterCapabilitySchema = z30.enum([
|
|
4005
4076
|
"raw-request-events",
|
|
4006
4077
|
"aggregate-request-metrics",
|
|
4007
4078
|
"request-url",
|
|
@@ -4012,214 +4083,214 @@ var trafficAdapterCapabilitySchema = z29.enum([
|
|
|
4012
4083
|
"cursor-pull"
|
|
4013
4084
|
]);
|
|
4014
4085
|
var TrafficAdapterCapabilities = trafficAdapterCapabilitySchema.enum;
|
|
4015
|
-
var trafficEvidenceKindSchema =
|
|
4086
|
+
var trafficEvidenceKindSchema = z30.enum(["raw-request", "aggregate-bucket"]);
|
|
4016
4087
|
var TrafficEvidenceKinds = trafficEvidenceKindSchema.enum;
|
|
4017
|
-
var trafficEventConfidenceSchema =
|
|
4088
|
+
var trafficEventConfidenceSchema = z30.enum(["observed", "provider-aggregated", "inferred"]);
|
|
4018
4089
|
var TrafficEventConfidences = trafficEventConfidenceSchema.enum;
|
|
4019
|
-
var trafficProviderResourceSchema =
|
|
4020
|
-
type:
|
|
4021
|
-
labels:
|
|
4090
|
+
var trafficProviderResourceSchema = z30.object({
|
|
4091
|
+
type: z30.string().nullable(),
|
|
4092
|
+
labels: z30.record(z30.string(), z30.string())
|
|
4022
4093
|
});
|
|
4023
|
-
var normalizedTrafficRequestSchema =
|
|
4094
|
+
var normalizedTrafficRequestSchema = z30.object({
|
|
4024
4095
|
sourceType: trafficSourceTypeSchema,
|
|
4025
|
-
evidenceKind:
|
|
4026
|
-
confidence:
|
|
4027
|
-
eventId:
|
|
4028
|
-
observedAt:
|
|
4029
|
-
method:
|
|
4030
|
-
requestUrl:
|
|
4031
|
-
host:
|
|
4032
|
-
path:
|
|
4033
|
-
queryString:
|
|
4034
|
-
status:
|
|
4035
|
-
userAgent:
|
|
4036
|
-
remoteIp:
|
|
4037
|
-
referer:
|
|
4038
|
-
latencyMs:
|
|
4039
|
-
requestSizeBytes:
|
|
4040
|
-
responseSizeBytes:
|
|
4096
|
+
evidenceKind: z30.literal(TrafficEvidenceKinds["raw-request"]),
|
|
4097
|
+
confidence: z30.literal(TrafficEventConfidences.observed),
|
|
4098
|
+
eventId: z30.string().min(1),
|
|
4099
|
+
observedAt: z30.string().min(1),
|
|
4100
|
+
method: z30.string().nullable(),
|
|
4101
|
+
requestUrl: z30.string().nullable(),
|
|
4102
|
+
host: z30.string().nullable(),
|
|
4103
|
+
path: z30.string().min(1),
|
|
4104
|
+
queryString: z30.string().nullable(),
|
|
4105
|
+
status: z30.number().int().nullable(),
|
|
4106
|
+
userAgent: z30.string().nullable(),
|
|
4107
|
+
remoteIp: z30.string().nullable(),
|
|
4108
|
+
referer: z30.string().nullable(),
|
|
4109
|
+
latencyMs: z30.number().nullable(),
|
|
4110
|
+
requestSizeBytes: z30.number().int().nullable(),
|
|
4111
|
+
responseSizeBytes: z30.number().int().nullable(),
|
|
4041
4112
|
providerResource: trafficProviderResourceSchema,
|
|
4042
|
-
providerLabels:
|
|
4113
|
+
providerLabels: z30.record(z30.string(), z30.string())
|
|
4043
4114
|
});
|
|
4044
|
-
var normalizedTrafficPullPageSchema =
|
|
4045
|
-
events:
|
|
4046
|
-
rawEntryCount:
|
|
4047
|
-
skippedEntryCount:
|
|
4048
|
-
nextPageToken:
|
|
4049
|
-
filter:
|
|
4115
|
+
var normalizedTrafficPullPageSchema = z30.object({
|
|
4116
|
+
events: z30.array(normalizedTrafficRequestSchema),
|
|
4117
|
+
rawEntryCount: z30.number().int().nonnegative(),
|
|
4118
|
+
skippedEntryCount: z30.number().int().nonnegative(),
|
|
4119
|
+
nextPageToken: z30.string().optional(),
|
|
4120
|
+
filter: z30.string()
|
|
4050
4121
|
});
|
|
4051
|
-
var trafficSourceStatusSchema =
|
|
4122
|
+
var trafficSourceStatusSchema = z30.enum(["connected", "paused", "error", "archived"]);
|
|
4052
4123
|
var TrafficSourceStatuses = trafficSourceStatusSchema.enum;
|
|
4053
|
-
var trafficSourceAuthModeSchema =
|
|
4124
|
+
var trafficSourceAuthModeSchema = z30.enum(["oauth", "service-account"]);
|
|
4054
4125
|
var TrafficSourceAuthModes = trafficSourceAuthModeSchema.enum;
|
|
4055
|
-
var verificationStatusSchema =
|
|
4126
|
+
var verificationStatusSchema = z30.enum(["verified", "claimed_unverified", "unknown_ai_like"]);
|
|
4056
4127
|
var VerificationStatuses = verificationStatusSchema.enum;
|
|
4057
|
-
var cloudRunSourceConfigSchema =
|
|
4058
|
-
gcpProjectId:
|
|
4059
|
-
serviceName:
|
|
4060
|
-
location:
|
|
4128
|
+
var cloudRunSourceConfigSchema = z30.object({
|
|
4129
|
+
gcpProjectId: z30.string().min(1),
|
|
4130
|
+
serviceName: z30.string().nullable().optional(),
|
|
4131
|
+
location: z30.string().nullable().optional(),
|
|
4061
4132
|
authMode: trafficSourceAuthModeSchema
|
|
4062
4133
|
});
|
|
4063
|
-
var wordpressTrafficSourceConfigSchema =
|
|
4064
|
-
baseUrl:
|
|
4065
|
-
username:
|
|
4134
|
+
var wordpressTrafficSourceConfigSchema = z30.object({
|
|
4135
|
+
baseUrl: z30.string().url(),
|
|
4136
|
+
username: z30.string().min(1)
|
|
4066
4137
|
});
|
|
4067
|
-
var vercelTrafficEnvironmentSchema =
|
|
4138
|
+
var vercelTrafficEnvironmentSchema = z30.enum(["production", "preview"]);
|
|
4068
4139
|
var VercelTrafficEnvironments = vercelTrafficEnvironmentSchema.enum;
|
|
4069
|
-
var vercelTrafficSourceConfigSchema =
|
|
4140
|
+
var vercelTrafficSourceConfigSchema = z30.object({
|
|
4070
4141
|
/** Vercel project id (e.g. `prj_...`). */
|
|
4071
|
-
projectId:
|
|
4142
|
+
projectId: z30.string().min(1),
|
|
4072
4143
|
/** Vercel team or account id: the org that owns the project. */
|
|
4073
|
-
teamId:
|
|
4144
|
+
teamId: z30.string().min(1),
|
|
4074
4145
|
environment: vercelTrafficEnvironmentSchema
|
|
4075
4146
|
});
|
|
4076
|
-
var trafficSourceDtoSchema =
|
|
4077
|
-
id:
|
|
4078
|
-
projectId:
|
|
4147
|
+
var trafficSourceDtoSchema = z30.object({
|
|
4148
|
+
id: z30.string(),
|
|
4149
|
+
projectId: z30.string(),
|
|
4079
4150
|
sourceType: trafficSourceTypeSchema,
|
|
4080
|
-
displayName:
|
|
4151
|
+
displayName: z30.string(),
|
|
4081
4152
|
status: trafficSourceStatusSchema,
|
|
4082
|
-
lastSyncedAt:
|
|
4083
|
-
lastCursor:
|
|
4084
|
-
lastError:
|
|
4085
|
-
archivedAt:
|
|
4086
|
-
config:
|
|
4087
|
-
createdAt:
|
|
4088
|
-
updatedAt:
|
|
4089
|
-
});
|
|
4090
|
-
var trafficConnectCloudRunRequestSchema =
|
|
4091
|
-
gcpProjectId:
|
|
4092
|
-
serviceName:
|
|
4093
|
-
location:
|
|
4094
|
-
displayName:
|
|
4153
|
+
lastSyncedAt: z30.string().nullable(),
|
|
4154
|
+
lastCursor: z30.string().nullable(),
|
|
4155
|
+
lastError: z30.string().nullable(),
|
|
4156
|
+
archivedAt: z30.string().nullable(),
|
|
4157
|
+
config: z30.record(z30.string(), z30.unknown()),
|
|
4158
|
+
createdAt: z30.string(),
|
|
4159
|
+
updatedAt: z30.string()
|
|
4160
|
+
});
|
|
4161
|
+
var trafficConnectCloudRunRequestSchema = z30.object({
|
|
4162
|
+
gcpProjectId: z30.string().min(1),
|
|
4163
|
+
serviceName: z30.string().min(1).optional(),
|
|
4164
|
+
location: z30.string().min(1).optional(),
|
|
4165
|
+
displayName: z30.string().min(1).optional(),
|
|
4095
4166
|
/** Service-account JSON content (string). When omitted, defaults to OAuth via `canonry google connect <project> --type ga4` flow. */
|
|
4096
|
-
keyJson:
|
|
4167
|
+
keyJson: z30.string().optional()
|
|
4097
4168
|
});
|
|
4098
|
-
var trafficConnectWordpressRequestSchema =
|
|
4099
|
-
baseUrl:
|
|
4100
|
-
username:
|
|
4169
|
+
var trafficConnectWordpressRequestSchema = z30.object({
|
|
4170
|
+
baseUrl: z30.string().url(),
|
|
4171
|
+
username: z30.string().min(1),
|
|
4101
4172
|
/** WordPress Application Password (the same auth used by the content client). */
|
|
4102
|
-
applicationPassword:
|
|
4103
|
-
displayName:
|
|
4173
|
+
applicationPassword: z30.string().min(1),
|
|
4174
|
+
displayName: z30.string().min(1).optional()
|
|
4104
4175
|
});
|
|
4105
|
-
var trafficConnectVercelRequestSchema =
|
|
4176
|
+
var trafficConnectVercelRequestSchema = z30.object({
|
|
4106
4177
|
/** Vercel project id (e.g. `prj_...`) — from the Vercel dashboard or `.vercel/project.json`. */
|
|
4107
|
-
projectId:
|
|
4178
|
+
projectId: z30.string().min(1),
|
|
4108
4179
|
/** Vercel team or account id: the org that owns the project ("orgId" in .vercel/project.json). */
|
|
4109
|
-
teamId:
|
|
4180
|
+
teamId: z30.string().min(1),
|
|
4110
4181
|
/** Vercel personal access token. Stored in `~/.canonry/config.yaml`, never the DB. */
|
|
4111
|
-
token:
|
|
4182
|
+
token: z30.string().min(1),
|
|
4112
4183
|
/** Which deployment environment's request logs to pull. Default: `production`. */
|
|
4113
4184
|
environment: vercelTrafficEnvironmentSchema.optional(),
|
|
4114
|
-
displayName:
|
|
4185
|
+
displayName: z30.string().min(1).optional()
|
|
4115
4186
|
});
|
|
4116
|
-
var trafficSyncResponseSchema =
|
|
4117
|
-
sourceId:
|
|
4118
|
-
runId:
|
|
4119
|
-
syncedAt:
|
|
4120
|
-
pulledEvents:
|
|
4187
|
+
var trafficSyncResponseSchema = z30.object({
|
|
4188
|
+
sourceId: z30.string(),
|
|
4189
|
+
runId: z30.string(),
|
|
4190
|
+
syncedAt: z30.string(),
|
|
4191
|
+
pulledEvents: z30.number().int().nonnegative(),
|
|
4121
4192
|
/** Self-traffic events (Canonry's own tooling) dropped before rollup. */
|
|
4122
|
-
selfTrafficExcluded:
|
|
4123
|
-
crawlerHits:
|
|
4124
|
-
aiUserFetchHits:
|
|
4125
|
-
aiReferralHits:
|
|
4126
|
-
unknownHits:
|
|
4127
|
-
crawlerBucketRows:
|
|
4128
|
-
aiUserFetchBucketRows:
|
|
4129
|
-
aiReferralBucketRows:
|
|
4130
|
-
sampleRows:
|
|
4131
|
-
windowStart:
|
|
4132
|
-
windowEnd:
|
|
4133
|
-
});
|
|
4134
|
-
var trafficBackfillRequestSchema =
|
|
4193
|
+
selfTrafficExcluded: z30.number().int().nonnegative(),
|
|
4194
|
+
crawlerHits: z30.number().int().nonnegative(),
|
|
4195
|
+
aiUserFetchHits: z30.number().int().nonnegative(),
|
|
4196
|
+
aiReferralHits: z30.number().int().nonnegative(),
|
|
4197
|
+
unknownHits: z30.number().int().nonnegative(),
|
|
4198
|
+
crawlerBucketRows: z30.number().int().nonnegative(),
|
|
4199
|
+
aiUserFetchBucketRows: z30.number().int().nonnegative(),
|
|
4200
|
+
aiReferralBucketRows: z30.number().int().nonnegative(),
|
|
4201
|
+
sampleRows: z30.number().int().nonnegative(),
|
|
4202
|
+
windowStart: z30.string(),
|
|
4203
|
+
windowEnd: z30.string()
|
|
4204
|
+
});
|
|
4205
|
+
var trafficBackfillRequestSchema = z30.object({
|
|
4135
4206
|
/** Lookback window in days. Capped server-side at the upstream log retention ceiling (Cloud Logging _Default = 30d). Default: 30. */
|
|
4136
|
-
days:
|
|
4207
|
+
days: z30.number().int().positive().optional()
|
|
4137
4208
|
});
|
|
4138
|
-
var trafficResetRequestSchema =
|
|
4139
|
-
advanceToNow:
|
|
4209
|
+
var trafficResetRequestSchema = z30.object({
|
|
4210
|
+
advanceToNow: z30.literal(true)
|
|
4140
4211
|
});
|
|
4141
|
-
var trafficBackfillResponseSchema =
|
|
4142
|
-
sourceId:
|
|
4143
|
-
runId:
|
|
4212
|
+
var trafficBackfillResponseSchema = z30.object({
|
|
4213
|
+
sourceId: z30.string(),
|
|
4214
|
+
runId: z30.string(),
|
|
4144
4215
|
status: runStatusSchema,
|
|
4145
|
-
windowStart:
|
|
4146
|
-
windowEnd:
|
|
4216
|
+
windowStart: z30.string(),
|
|
4217
|
+
windowEnd: z30.string(),
|
|
4147
4218
|
/** Days actually used after server-side clamping (≤ requested). */
|
|
4148
|
-
daysRequested:
|
|
4149
|
-
daysApplied:
|
|
4219
|
+
daysRequested: z30.number().int().positive(),
|
|
4220
|
+
daysApplied: z30.number().int().positive()
|
|
4150
4221
|
});
|
|
4151
|
-
var trafficSourceTotalsSchema =
|
|
4152
|
-
crawlerHits:
|
|
4153
|
-
aiUserFetchHits:
|
|
4154
|
-
aiReferralHits:
|
|
4155
|
-
sampleCount:
|
|
4222
|
+
var trafficSourceTotalsSchema = z30.object({
|
|
4223
|
+
crawlerHits: z30.number().int().nonnegative(),
|
|
4224
|
+
aiUserFetchHits: z30.number().int().nonnegative(),
|
|
4225
|
+
aiReferralHits: z30.number().int().nonnegative(),
|
|
4226
|
+
sampleCount: z30.number().int().nonnegative()
|
|
4156
4227
|
});
|
|
4157
|
-
var trafficSourceListResponseSchema =
|
|
4158
|
-
sources:
|
|
4228
|
+
var trafficSourceListResponseSchema = z30.object({
|
|
4229
|
+
sources: z30.array(trafficSourceDtoSchema)
|
|
4159
4230
|
});
|
|
4160
4231
|
var trafficSourceDetailDtoSchema = trafficSourceDtoSchema.extend({
|
|
4161
4232
|
totals24h: trafficSourceTotalsSchema,
|
|
4162
|
-
latestRun:
|
|
4163
|
-
runId:
|
|
4233
|
+
latestRun: z30.object({
|
|
4234
|
+
runId: z30.string(),
|
|
4164
4235
|
status: runStatusSchema,
|
|
4165
|
-
startedAt:
|
|
4166
|
-
finishedAt:
|
|
4167
|
-
error:
|
|
4236
|
+
startedAt: z30.string().nullable(),
|
|
4237
|
+
finishedAt: z30.string().nullable(),
|
|
4238
|
+
error: z30.string().nullable()
|
|
4168
4239
|
}).nullable()
|
|
4169
4240
|
});
|
|
4170
|
-
var trafficStatusResponseSchema =
|
|
4171
|
-
sources:
|
|
4241
|
+
var trafficStatusResponseSchema = z30.object({
|
|
4242
|
+
sources: z30.array(trafficSourceDetailDtoSchema)
|
|
4172
4243
|
});
|
|
4173
|
-
var trafficEventKindSchema =
|
|
4244
|
+
var trafficEventKindSchema = z30.enum(["crawler", "ai-user-fetch", "ai-referral"]);
|
|
4174
4245
|
var TrafficEventKinds = trafficEventKindSchema.enum;
|
|
4175
|
-
var trafficCrawlerEventEntrySchema =
|
|
4176
|
-
kind:
|
|
4177
|
-
sourceId:
|
|
4178
|
-
tsHour:
|
|
4179
|
-
botId:
|
|
4180
|
-
operator:
|
|
4181
|
-
verificationStatus:
|
|
4182
|
-
pathNormalized:
|
|
4183
|
-
status:
|
|
4184
|
-
hits:
|
|
4185
|
-
});
|
|
4186
|
-
var trafficAiUserFetchEventEntrySchema =
|
|
4187
|
-
kind:
|
|
4188
|
-
sourceId:
|
|
4189
|
-
tsHour:
|
|
4190
|
-
botId:
|
|
4191
|
-
operator:
|
|
4192
|
-
verificationStatus:
|
|
4193
|
-
pathNormalized:
|
|
4194
|
-
status:
|
|
4195
|
-
hits:
|
|
4196
|
-
});
|
|
4197
|
-
var trafficAiReferralEventEntrySchema =
|
|
4198
|
-
kind:
|
|
4199
|
-
sourceId:
|
|
4200
|
-
tsHour:
|
|
4201
|
-
product:
|
|
4202
|
-
operator:
|
|
4203
|
-
sourceDomain:
|
|
4204
|
-
evidenceType:
|
|
4205
|
-
landingPathNormalized:
|
|
4206
|
-
status:
|
|
4207
|
-
hits:
|
|
4208
|
-
});
|
|
4209
|
-
var trafficEventEntrySchema =
|
|
4246
|
+
var trafficCrawlerEventEntrySchema = z30.object({
|
|
4247
|
+
kind: z30.literal(TrafficEventKinds.crawler),
|
|
4248
|
+
sourceId: z30.string(),
|
|
4249
|
+
tsHour: z30.string(),
|
|
4250
|
+
botId: z30.string(),
|
|
4251
|
+
operator: z30.string(),
|
|
4252
|
+
verificationStatus: z30.string(),
|
|
4253
|
+
pathNormalized: z30.string(),
|
|
4254
|
+
status: z30.number().int(),
|
|
4255
|
+
hits: z30.number().int().nonnegative()
|
|
4256
|
+
});
|
|
4257
|
+
var trafficAiUserFetchEventEntrySchema = z30.object({
|
|
4258
|
+
kind: z30.literal(TrafficEventKinds["ai-user-fetch"]),
|
|
4259
|
+
sourceId: z30.string(),
|
|
4260
|
+
tsHour: z30.string(),
|
|
4261
|
+
botId: z30.string(),
|
|
4262
|
+
operator: z30.string(),
|
|
4263
|
+
verificationStatus: z30.string(),
|
|
4264
|
+
pathNormalized: z30.string(),
|
|
4265
|
+
status: z30.number().int(),
|
|
4266
|
+
hits: z30.number().int().nonnegative()
|
|
4267
|
+
});
|
|
4268
|
+
var trafficAiReferralEventEntrySchema = z30.object({
|
|
4269
|
+
kind: z30.literal(TrafficEventKinds["ai-referral"]),
|
|
4270
|
+
sourceId: z30.string(),
|
|
4271
|
+
tsHour: z30.string(),
|
|
4272
|
+
product: z30.string(),
|
|
4273
|
+
operator: z30.string(),
|
|
4274
|
+
sourceDomain: z30.string(),
|
|
4275
|
+
evidenceType: z30.string(),
|
|
4276
|
+
landingPathNormalized: z30.string(),
|
|
4277
|
+
status: z30.number().int(),
|
|
4278
|
+
hits: z30.number().int().nonnegative()
|
|
4279
|
+
});
|
|
4280
|
+
var trafficEventEntrySchema = z30.discriminatedUnion("kind", [
|
|
4210
4281
|
trafficCrawlerEventEntrySchema,
|
|
4211
4282
|
trafficAiUserFetchEventEntrySchema,
|
|
4212
4283
|
trafficAiReferralEventEntrySchema
|
|
4213
4284
|
]);
|
|
4214
|
-
var trafficEventsResponseSchema =
|
|
4215
|
-
windowStart:
|
|
4216
|
-
windowEnd:
|
|
4217
|
-
totals:
|
|
4218
|
-
crawlerHits:
|
|
4219
|
-
aiUserFetchHits:
|
|
4220
|
-
aiReferralHits:
|
|
4285
|
+
var trafficEventsResponseSchema = z30.object({
|
|
4286
|
+
windowStart: z30.string(),
|
|
4287
|
+
windowEnd: z30.string(),
|
|
4288
|
+
totals: z30.object({
|
|
4289
|
+
crawlerHits: z30.number().int().nonnegative(),
|
|
4290
|
+
aiUserFetchHits: z30.number().int().nonnegative(),
|
|
4291
|
+
aiReferralHits: z30.number().int().nonnegative()
|
|
4221
4292
|
}),
|
|
4222
|
-
events:
|
|
4293
|
+
events: z30.array(trafficEventEntrySchema)
|
|
4223
4294
|
});
|
|
4224
4295
|
|
|
4225
4296
|
// ../contracts/src/embeddings.ts
|
|
@@ -4332,6 +4403,12 @@ function formatDateRange(start, end) {
|
|
|
4332
4403
|
if (start && end) return `${formatDate(start)} \u2192 ${formatDate(end)}`;
|
|
4333
4404
|
return formatDate(start || end);
|
|
4334
4405
|
}
|
|
4406
|
+
var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
4407
|
+
function parseInclusiveEndMs(iso) {
|
|
4408
|
+
const ms = Date.parse(iso);
|
|
4409
|
+
if (Number.isNaN(ms)) return null;
|
|
4410
|
+
return DATE_ONLY_PATTERN.test(iso) ? ms + 864e5 - 1 : ms;
|
|
4411
|
+
}
|
|
4335
4412
|
function deltaPercent(current, prior) {
|
|
4336
4413
|
if (prior <= 0) return null;
|
|
4337
4414
|
return Math.round((current - prior) / prior * 100);
|
|
@@ -4350,105 +4427,105 @@ function formatDeltaCopy(d, suffix, windowLabel = "vs prior 7 days") {
|
|
|
4350
4427
|
}
|
|
4351
4428
|
|
|
4352
4429
|
// ../contracts/src/ads.ts
|
|
4353
|
-
import { z as
|
|
4354
|
-
var adsConnectRequestSchema =
|
|
4430
|
+
import { z as z31 } from "zod";
|
|
4431
|
+
var adsConnectRequestSchema = z31.object({
|
|
4355
4432
|
/** Ads Manager "SDK key" scoped to one ad account. Stored in config.yaml, never the DB. */
|
|
4356
|
-
apiKey:
|
|
4357
|
-
});
|
|
4358
|
-
var adsConnectionStatusDtoSchema =
|
|
4359
|
-
connected:
|
|
4360
|
-
adAccountId:
|
|
4361
|
-
displayName:
|
|
4362
|
-
currencyCode:
|
|
4363
|
-
timezone:
|
|
4364
|
-
status:
|
|
4365
|
-
lastSyncedAt:
|
|
4366
|
-
});
|
|
4367
|
-
var adsDisconnectResponseSchema =
|
|
4368
|
-
disconnected:
|
|
4369
|
-
});
|
|
4370
|
-
var adsSyncResponseSchema =
|
|
4371
|
-
runId:
|
|
4372
|
-
status:
|
|
4373
|
-
});
|
|
4374
|
-
var adsCreativeDtoSchema =
|
|
4375
|
-
type:
|
|
4376
|
-
title:
|
|
4377
|
-
body:
|
|
4378
|
-
targetUrl:
|
|
4379
|
-
});
|
|
4380
|
-
var adsAdDtoSchema =
|
|
4381
|
-
id:
|
|
4382
|
-
adGroupId:
|
|
4383
|
-
name:
|
|
4384
|
-
status:
|
|
4385
|
-
reviewStatus:
|
|
4433
|
+
apiKey: z31.string().min(1)
|
|
4434
|
+
});
|
|
4435
|
+
var adsConnectionStatusDtoSchema = z31.object({
|
|
4436
|
+
connected: z31.boolean(),
|
|
4437
|
+
adAccountId: z31.string().nullable().optional(),
|
|
4438
|
+
displayName: z31.string().nullable().optional(),
|
|
4439
|
+
currencyCode: z31.string().nullable().optional(),
|
|
4440
|
+
timezone: z31.string().nullable().optional(),
|
|
4441
|
+
status: z31.string().nullable().optional(),
|
|
4442
|
+
lastSyncedAt: z31.string().nullable().optional()
|
|
4443
|
+
});
|
|
4444
|
+
var adsDisconnectResponseSchema = z31.object({
|
|
4445
|
+
disconnected: z31.boolean()
|
|
4446
|
+
});
|
|
4447
|
+
var adsSyncResponseSchema = z31.object({
|
|
4448
|
+
runId: z31.string(),
|
|
4449
|
+
status: z31.string()
|
|
4450
|
+
});
|
|
4451
|
+
var adsCreativeDtoSchema = z31.object({
|
|
4452
|
+
type: z31.string().nullable().optional(),
|
|
4453
|
+
title: z31.string().nullable().optional(),
|
|
4454
|
+
body: z31.string().nullable().optional(),
|
|
4455
|
+
targetUrl: z31.string().nullable().optional()
|
|
4456
|
+
});
|
|
4457
|
+
var adsAdDtoSchema = z31.object({
|
|
4458
|
+
id: z31.string(),
|
|
4459
|
+
adGroupId: z31.string(),
|
|
4460
|
+
name: z31.string(),
|
|
4461
|
+
status: z31.string(),
|
|
4462
|
+
reviewStatus: z31.string().nullable().optional(),
|
|
4386
4463
|
creative: adsCreativeDtoSchema.nullable().optional()
|
|
4387
4464
|
});
|
|
4388
|
-
var adsAdGroupDtoSchema =
|
|
4389
|
-
id:
|
|
4390
|
-
campaignId:
|
|
4391
|
-
name:
|
|
4392
|
-
status:
|
|
4393
|
-
billingEventType:
|
|
4394
|
-
maxBidMicros:
|
|
4465
|
+
var adsAdGroupDtoSchema = z31.object({
|
|
4466
|
+
id: z31.string(),
|
|
4467
|
+
campaignId: z31.string(),
|
|
4468
|
+
name: z31.string(),
|
|
4469
|
+
status: z31.string(),
|
|
4470
|
+
billingEventType: z31.string().nullable().optional(),
|
|
4471
|
+
maxBidMicros: z31.number().int().nullable().optional(),
|
|
4395
4472
|
/**
|
|
4396
4473
|
* The targeting primitive: entries are multi-line strings of
|
|
4397
4474
|
* newline-separated example queries (the live Ads Manager format).
|
|
4398
4475
|
*/
|
|
4399
|
-
contextHints:
|
|
4400
|
-
ads:
|
|
4401
|
-
});
|
|
4402
|
-
var adsCampaignDtoSchema =
|
|
4403
|
-
id:
|
|
4404
|
-
name:
|
|
4405
|
-
status:
|
|
4406
|
-
biddingType:
|
|
4407
|
-
dailySpendLimitMicros:
|
|
4408
|
-
lifetimeSpendLimitMicros:
|
|
4409
|
-
adGroups:
|
|
4410
|
-
});
|
|
4411
|
-
var adsCampaignListResponseSchema =
|
|
4412
|
-
campaigns:
|
|
4413
|
-
});
|
|
4414
|
-
var adsInsightLevelSchema =
|
|
4476
|
+
contextHints: z31.array(z31.string()).default([]),
|
|
4477
|
+
ads: z31.array(adsAdDtoSchema).default([])
|
|
4478
|
+
});
|
|
4479
|
+
var adsCampaignDtoSchema = z31.object({
|
|
4480
|
+
id: z31.string(),
|
|
4481
|
+
name: z31.string(),
|
|
4482
|
+
status: z31.string(),
|
|
4483
|
+
biddingType: z31.string().nullable().optional(),
|
|
4484
|
+
dailySpendLimitMicros: z31.number().int().nullable().optional(),
|
|
4485
|
+
lifetimeSpendLimitMicros: z31.number().int().nullable().optional(),
|
|
4486
|
+
adGroups: z31.array(adsAdGroupDtoSchema).default([])
|
|
4487
|
+
});
|
|
4488
|
+
var adsCampaignListResponseSchema = z31.object({
|
|
4489
|
+
campaigns: z31.array(adsCampaignDtoSchema)
|
|
4490
|
+
});
|
|
4491
|
+
var adsInsightLevelSchema = z31.enum(["campaign", "ad_group"]);
|
|
4415
4492
|
var AdsInsightLevels = adsInsightLevelSchema.enum;
|
|
4416
|
-
var adsInsightRowDtoSchema =
|
|
4493
|
+
var adsInsightRowDtoSchema = z31.object({
|
|
4417
4494
|
level: adsInsightLevelSchema,
|
|
4418
|
-
entityId:
|
|
4419
|
-
date:
|
|
4420
|
-
impressions:
|
|
4421
|
-
clicks:
|
|
4422
|
-
spendMicros:
|
|
4495
|
+
entityId: z31.string(),
|
|
4496
|
+
date: z31.string(),
|
|
4497
|
+
impressions: z31.number().int(),
|
|
4498
|
+
clicks: z31.number().int(),
|
|
4499
|
+
spendMicros: z31.number().int(),
|
|
4423
4500
|
/** clicks / impressions; null when impressions is 0. */
|
|
4424
|
-
ctr:
|
|
4501
|
+
ctr: z31.number().nullable(),
|
|
4425
4502
|
/** spendMicros / clicks, rounded to integer micros; null when clicks is 0. */
|
|
4426
|
-
cpcMicros:
|
|
4503
|
+
cpcMicros: z31.number().int().nullable()
|
|
4427
4504
|
});
|
|
4428
|
-
var adsInsightsResponseSchema =
|
|
4429
|
-
rows:
|
|
4505
|
+
var adsInsightsResponseSchema = z31.object({
|
|
4506
|
+
rows: z31.array(adsInsightRowDtoSchema),
|
|
4430
4507
|
/** Account currency for rendering spend/cpc; null before the first sync. */
|
|
4431
|
-
currencyCode:
|
|
4432
|
-
});
|
|
4433
|
-
var adsTotalsDtoSchema =
|
|
4434
|
-
impressions:
|
|
4435
|
-
clicks:
|
|
4436
|
-
spendMicros:
|
|
4437
|
-
ctr:
|
|
4438
|
-
cpcMicros:
|
|
4439
|
-
});
|
|
4440
|
-
var adsSummaryDtoSchema =
|
|
4441
|
-
connected:
|
|
4442
|
-
displayName:
|
|
4443
|
-
currencyCode:
|
|
4444
|
-
lastSyncedAt:
|
|
4445
|
-
campaignCount:
|
|
4446
|
-
adGroupCount:
|
|
4447
|
-
adCount:
|
|
4508
|
+
currencyCode: z31.string().nullable().optional()
|
|
4509
|
+
});
|
|
4510
|
+
var adsTotalsDtoSchema = z31.object({
|
|
4511
|
+
impressions: z31.number().int(),
|
|
4512
|
+
clicks: z31.number().int(),
|
|
4513
|
+
spendMicros: z31.number().int(),
|
|
4514
|
+
ctr: z31.number().nullable(),
|
|
4515
|
+
cpcMicros: z31.number().int().nullable()
|
|
4516
|
+
});
|
|
4517
|
+
var adsSummaryDtoSchema = z31.object({
|
|
4518
|
+
connected: z31.boolean(),
|
|
4519
|
+
displayName: z31.string().nullable().optional(),
|
|
4520
|
+
currencyCode: z31.string().nullable().optional(),
|
|
4521
|
+
lastSyncedAt: z31.string().nullable().optional(),
|
|
4522
|
+
campaignCount: z31.number().int(),
|
|
4523
|
+
adGroupCount: z31.number().int(),
|
|
4524
|
+
adCount: z31.number().int(),
|
|
4448
4525
|
/** Date range the totals cover (oldest/newest rollup date), null when empty. */
|
|
4449
|
-
window:
|
|
4450
|
-
from:
|
|
4451
|
-
to:
|
|
4526
|
+
window: z31.object({
|
|
4527
|
+
from: z31.string().nullable(),
|
|
4528
|
+
to: z31.string().nullable()
|
|
4452
4529
|
}),
|
|
4453
4530
|
/** Campaign-level rollup totals over the window (levels are not summed across). */
|
|
4454
4531
|
totals: adsTotalsDtoSchema
|
|
@@ -4685,6 +4762,7 @@ export {
|
|
|
4685
4762
|
sourceBreakdownDtoSchema,
|
|
4686
4763
|
parseWindow,
|
|
4687
4764
|
windowCutoff,
|
|
4765
|
+
visibilityStatsDtoSchema,
|
|
4688
4766
|
ga4StatusDtoSchema,
|
|
4689
4767
|
ga4SyncResponseDtoSchema,
|
|
4690
4768
|
ga4AiReferralHistoryEntrySchema,
|
|
@@ -4783,6 +4861,7 @@ export {
|
|
|
4783
4861
|
formatDate,
|
|
4784
4862
|
formatIsoDate,
|
|
4785
4863
|
formatDateRange,
|
|
4864
|
+
parseInclusiveEndMs,
|
|
4786
4865
|
deltaPercent,
|
|
4787
4866
|
deltaTone,
|
|
4788
4867
|
formatDeltaCopy,
|