@ainyc/canonry 2.2.1 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/canonry-setup/SKILL.md +7 -7
- package/assets/assets/{index-J73csS93.js → index-Bmnz-wvT.js} +54 -54
- package/assets/index.html +1 -1
- package/dist/{chunk-2QNWFP6R.js → chunk-MXUOJWNL.js} +170 -131
- package/dist/cli.js +132 -104
- package/dist/index.js +1 -1
- package/package.json +5 -5
package/assets/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
13
13
|
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />
|
|
14
14
|
<title>Canonry</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-Bmnz-wvT.js"></script>
|
|
16
16
|
<link rel="stylesheet" crossorigin href="./assets/index-yF1fs-OW.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
@@ -292,6 +292,11 @@ function usageError(displayMessage, options) {
|
|
|
292
292
|
details: options?.details
|
|
293
293
|
});
|
|
294
294
|
}
|
|
295
|
+
function isEndpointMissing(err) {
|
|
296
|
+
if (!(err instanceof CliError)) return false;
|
|
297
|
+
const status = err.details?.httpStatus;
|
|
298
|
+
return status === 404 || status === 405;
|
|
299
|
+
}
|
|
295
300
|
function printCliError(err, format) {
|
|
296
301
|
if (format === "json") {
|
|
297
302
|
if (err instanceof CliError) {
|
|
@@ -987,6 +992,13 @@ var querySnapshotDtoSchema = z8.object({
|
|
|
987
992
|
location: z8.string().nullable().optional(),
|
|
988
993
|
createdAt: z8.string()
|
|
989
994
|
});
|
|
995
|
+
var runDetailDtoSchema = runDtoSchema.extend({
|
|
996
|
+
snapshots: z8.array(querySnapshotDtoSchema).optional()
|
|
997
|
+
});
|
|
998
|
+
var latestProjectRunDtoSchema = z8.object({
|
|
999
|
+
totalRuns: z8.number().int().nonnegative(),
|
|
1000
|
+
run: runDetailDtoSchema.nullable()
|
|
1001
|
+
});
|
|
990
1002
|
var auditLogEntrySchema = z8.object({
|
|
991
1003
|
id: z8.string(),
|
|
992
1004
|
projectId: z8.string().nullable().optional(),
|
|
@@ -1996,7 +2008,7 @@ async function competitorRoutes(app) {
|
|
|
1996
2008
|
|
|
1997
2009
|
// ../api-routes/src/runs.ts
|
|
1998
2010
|
import crypto8 from "crypto";
|
|
1999
|
-
import { eq as eq7, asc, desc } from "drizzle-orm";
|
|
2011
|
+
import { eq as eq7, asc, desc, sql as sql2 } from "drizzle-orm";
|
|
2000
2012
|
|
|
2001
2013
|
// ../api-routes/src/run-queue.ts
|
|
2002
2014
|
import crypto7 from "crypto";
|
|
@@ -2136,6 +2148,19 @@ async function runRoutes(app, opts) {
|
|
|
2136
2148
|
const rows = limit == null ? app.db.select().from(runs).where(eq7(runs.projectId, project.id)).orderBy(asc(runs.createdAt)).all() : app.db.select().from(runs).where(eq7(runs.projectId, project.id)).orderBy(desc(runs.createdAt)).limit(limit).all().reverse();
|
|
2137
2149
|
return reply.send(rows.map(formatRun));
|
|
2138
2150
|
});
|
|
2151
|
+
app.get("/projects/:name/runs/latest", async (request, reply) => {
|
|
2152
|
+
const project = resolveProject(app.db, request.params.name);
|
|
2153
|
+
const countRow = app.db.select({ count: sql2`count(*)` }).from(runs).where(eq7(runs.projectId, project.id)).get();
|
|
2154
|
+
const totalRuns = countRow?.count ?? 0;
|
|
2155
|
+
const latestRun = app.db.select().from(runs).where(eq7(runs.projectId, project.id)).orderBy(desc(runs.createdAt)).limit(1).get();
|
|
2156
|
+
if (!latestRun) {
|
|
2157
|
+
return reply.send({ totalRuns: 0, run: null });
|
|
2158
|
+
}
|
|
2159
|
+
return reply.send({
|
|
2160
|
+
totalRuns,
|
|
2161
|
+
run: loadRunDetail(app, latestRun)
|
|
2162
|
+
});
|
|
2163
|
+
});
|
|
2139
2164
|
app.get("/runs", async (_request, reply) => {
|
|
2140
2165
|
const rows = app.db.select().from(runs).all();
|
|
2141
2166
|
return reply.send(rows.map(formatRun));
|
|
@@ -2224,55 +2249,7 @@ async function runRoutes(app, opts) {
|
|
|
2224
2249
|
app.get("/runs/:id", async (request, reply) => {
|
|
2225
2250
|
const run = app.db.select().from(runs).where(eq7(runs.id, request.params.id)).get();
|
|
2226
2251
|
if (!run) throw notFound("Run", request.params.id);
|
|
2227
|
-
|
|
2228
|
-
displayName: projects.displayName,
|
|
2229
|
-
canonicalDomain: projects.canonicalDomain,
|
|
2230
|
-
ownedDomains: projects.ownedDomains
|
|
2231
|
-
}).from(projects).where(eq7(projects.id, run.projectId)).get();
|
|
2232
|
-
const snapshots = app.db.select({
|
|
2233
|
-
id: querySnapshots.id,
|
|
2234
|
-
runId: querySnapshots.runId,
|
|
2235
|
-
keywordId: querySnapshots.keywordId,
|
|
2236
|
-
keyword: keywords.keyword,
|
|
2237
|
-
provider: querySnapshots.provider,
|
|
2238
|
-
model: querySnapshots.model,
|
|
2239
|
-
citationState: querySnapshots.citationState,
|
|
2240
|
-
answerMentioned: querySnapshots.answerMentioned,
|
|
2241
|
-
answerText: querySnapshots.answerText,
|
|
2242
|
-
citedDomains: querySnapshots.citedDomains,
|
|
2243
|
-
competitorOverlap: querySnapshots.competitorOverlap,
|
|
2244
|
-
recommendedCompetitors: querySnapshots.recommendedCompetitors,
|
|
2245
|
-
location: querySnapshots.location,
|
|
2246
|
-
rawResponse: querySnapshots.rawResponse,
|
|
2247
|
-
createdAt: querySnapshots.createdAt
|
|
2248
|
-
}).from(querySnapshots).leftJoin(keywords, eq7(querySnapshots.keywordId, keywords.id)).where(eq7(querySnapshots.runId, run.id)).all();
|
|
2249
|
-
return reply.send({
|
|
2250
|
-
...formatRun(run),
|
|
2251
|
-
snapshots: snapshots.map((s) => {
|
|
2252
|
-
const rawParsed = parseSnapshotRawResponse(s.rawResponse);
|
|
2253
|
-
const answerMentioned = project ? resolveSnapshotAnswerMentioned(s, project) : s.answerMentioned ?? false;
|
|
2254
|
-
return {
|
|
2255
|
-
id: s.id,
|
|
2256
|
-
runId: s.runId,
|
|
2257
|
-
keywordId: s.keywordId,
|
|
2258
|
-
keyword: s.keyword,
|
|
2259
|
-
provider: s.provider,
|
|
2260
|
-
citationState: s.citationState,
|
|
2261
|
-
answerMentioned,
|
|
2262
|
-
visibilityState: project ? resolveSnapshotVisibilityState(s, project) : answerMentioned ? "visible" : "not-visible",
|
|
2263
|
-
answerText: s.answerText,
|
|
2264
|
-
citedDomains: parseJsonColumn(s.citedDomains, []),
|
|
2265
|
-
competitorOverlap: parseJsonColumn(s.competitorOverlap, []),
|
|
2266
|
-
recommendedCompetitors: parseJsonColumn(s.recommendedCompetitors, []),
|
|
2267
|
-
matchedTerms: project ? resolveSnapshotMatchedTerms(s, project) : [],
|
|
2268
|
-
model: s.model ?? rawParsed.model,
|
|
2269
|
-
location: s.location,
|
|
2270
|
-
groundingSources: rawParsed.groundingSources,
|
|
2271
|
-
searchQueries: rawParsed.searchQueries,
|
|
2272
|
-
createdAt: s.createdAt
|
|
2273
|
-
};
|
|
2274
|
-
})
|
|
2275
|
-
});
|
|
2252
|
+
return reply.send(loadRunDetail(app, run));
|
|
2276
2253
|
});
|
|
2277
2254
|
}
|
|
2278
2255
|
function formatRun(row) {
|
|
@@ -2297,6 +2274,57 @@ function parseSnapshotRawResponse(raw) {
|
|
|
2297
2274
|
model: parsed.model ?? null
|
|
2298
2275
|
};
|
|
2299
2276
|
}
|
|
2277
|
+
function loadRunDetail(app, run) {
|
|
2278
|
+
const project = app.db.select({
|
|
2279
|
+
displayName: projects.displayName,
|
|
2280
|
+
canonicalDomain: projects.canonicalDomain,
|
|
2281
|
+
ownedDomains: projects.ownedDomains
|
|
2282
|
+
}).from(projects).where(eq7(projects.id, run.projectId)).get();
|
|
2283
|
+
const snapshots = app.db.select({
|
|
2284
|
+
id: querySnapshots.id,
|
|
2285
|
+
runId: querySnapshots.runId,
|
|
2286
|
+
keywordId: querySnapshots.keywordId,
|
|
2287
|
+
keyword: keywords.keyword,
|
|
2288
|
+
provider: querySnapshots.provider,
|
|
2289
|
+
model: querySnapshots.model,
|
|
2290
|
+
citationState: querySnapshots.citationState,
|
|
2291
|
+
answerMentioned: querySnapshots.answerMentioned,
|
|
2292
|
+
answerText: querySnapshots.answerText,
|
|
2293
|
+
citedDomains: querySnapshots.citedDomains,
|
|
2294
|
+
competitorOverlap: querySnapshots.competitorOverlap,
|
|
2295
|
+
recommendedCompetitors: querySnapshots.recommendedCompetitors,
|
|
2296
|
+
location: querySnapshots.location,
|
|
2297
|
+
rawResponse: querySnapshots.rawResponse,
|
|
2298
|
+
createdAt: querySnapshots.createdAt
|
|
2299
|
+
}).from(querySnapshots).leftJoin(keywords, eq7(querySnapshots.keywordId, keywords.id)).where(eq7(querySnapshots.runId, run.id)).all();
|
|
2300
|
+
return {
|
|
2301
|
+
...formatRun(run),
|
|
2302
|
+
snapshots: snapshots.map((s) => {
|
|
2303
|
+
const rawParsed = parseSnapshotRawResponse(s.rawResponse);
|
|
2304
|
+
const answerMentioned = project ? resolveSnapshotAnswerMentioned(s, project) : s.answerMentioned ?? false;
|
|
2305
|
+
return {
|
|
2306
|
+
id: s.id,
|
|
2307
|
+
runId: s.runId,
|
|
2308
|
+
keywordId: s.keywordId,
|
|
2309
|
+
keyword: s.keyword,
|
|
2310
|
+
provider: s.provider,
|
|
2311
|
+
citationState: s.citationState,
|
|
2312
|
+
answerMentioned,
|
|
2313
|
+
visibilityState: project ? resolveSnapshotVisibilityState(s, project) : answerMentioned ? "visible" : "not-visible",
|
|
2314
|
+
answerText: s.answerText,
|
|
2315
|
+
citedDomains: parseJsonColumn(s.citedDomains, []),
|
|
2316
|
+
competitorOverlap: parseJsonColumn(s.competitorOverlap, []),
|
|
2317
|
+
recommendedCompetitors: parseJsonColumn(s.recommendedCompetitors, []),
|
|
2318
|
+
matchedTerms: project ? resolveSnapshotMatchedTerms(s, project) : [],
|
|
2319
|
+
model: s.model ?? rawParsed.model,
|
|
2320
|
+
location: s.location,
|
|
2321
|
+
groundingSources: rawParsed.groundingSources,
|
|
2322
|
+
searchQueries: rawParsed.searchQueries,
|
|
2323
|
+
createdAt: s.createdAt
|
|
2324
|
+
};
|
|
2325
|
+
})
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2300
2328
|
|
|
2301
2329
|
// ../api-routes/src/apply.ts
|
|
2302
2330
|
import crypto10 from "crypto";
|
|
@@ -3930,6 +3958,16 @@ var routeCatalog = [
|
|
|
3930
3958
|
200: { description: "Runs returned." }
|
|
3931
3959
|
}
|
|
3932
3960
|
},
|
|
3961
|
+
{
|
|
3962
|
+
method: "get",
|
|
3963
|
+
path: "/api/v1/projects/{name}/runs/latest",
|
|
3964
|
+
summary: "Get the latest project run",
|
|
3965
|
+
tags: ["runs"],
|
|
3966
|
+
parameters: [nameParameter],
|
|
3967
|
+
responses: {
|
|
3968
|
+
200: { description: "Latest run returned." }
|
|
3969
|
+
}
|
|
3970
|
+
},
|
|
3933
3971
|
{
|
|
3934
3972
|
method: "get",
|
|
3935
3973
|
path: "/api/v1/runs",
|
|
@@ -5918,10 +5956,9 @@ async function snapshotRoutes(app, opts) {
|
|
|
5918
5956
|
|
|
5919
5957
|
// ../api-routes/src/telemetry.ts
|
|
5920
5958
|
async function telemetryRoutes(app, opts) {
|
|
5921
|
-
app.get("/telemetry", async (
|
|
5959
|
+
app.get("/telemetry", async () => {
|
|
5922
5960
|
if (!opts.getTelemetryStatus) {
|
|
5923
|
-
|
|
5924
|
-
return reply.status(err.statusCode).send(err.toJSON());
|
|
5961
|
+
throw notImplemented("Telemetry status is not available in this deployment");
|
|
5925
5962
|
}
|
|
5926
5963
|
const status = opts.getTelemetryStatus();
|
|
5927
5964
|
return {
|
|
@@ -5929,15 +5966,13 @@ async function telemetryRoutes(app, opts) {
|
|
|
5929
5966
|
anonymousId: status.anonymousId ? status.anonymousId.slice(0, 8) + "..." : void 0
|
|
5930
5967
|
};
|
|
5931
5968
|
});
|
|
5932
|
-
app.put("/telemetry", async (request
|
|
5969
|
+
app.put("/telemetry", async (request) => {
|
|
5933
5970
|
if (!opts.setTelemetryEnabled) {
|
|
5934
|
-
|
|
5935
|
-
return reply.status(err.statusCode).send(err.toJSON());
|
|
5971
|
+
throw notImplemented("Telemetry configuration is not available in this deployment");
|
|
5936
5972
|
}
|
|
5937
5973
|
const { enabled } = request.body ?? {};
|
|
5938
5974
|
if (typeof enabled !== "boolean") {
|
|
5939
|
-
|
|
5940
|
-
return reply.status(err.statusCode).send(err.toJSON());
|
|
5975
|
+
throw validationError("enabled (boolean) is required");
|
|
5941
5976
|
}
|
|
5942
5977
|
opts.setTelemetryEnabled(enabled);
|
|
5943
5978
|
const status = opts.getTelemetryStatus?.();
|
|
@@ -6190,7 +6225,7 @@ function formatNotification(row) {
|
|
|
6190
6225
|
|
|
6191
6226
|
// ../api-routes/src/google.ts
|
|
6192
6227
|
import crypto14 from "crypto";
|
|
6193
|
-
import { eq as eq14, and as and3, desc as desc5, sql as
|
|
6228
|
+
import { eq as eq14, and as and3, desc as desc5, sql as sql3 } from "drizzle-orm";
|
|
6194
6229
|
|
|
6195
6230
|
// ../integration-google/src/constants.ts
|
|
6196
6231
|
var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
@@ -7313,11 +7348,11 @@ async function googleRoutes(app, opts) {
|
|
|
7313
7348
|
const { startDate, endDate, query, page, limit } = request.query;
|
|
7314
7349
|
const cutoffDate = !startDate ? windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null : null;
|
|
7315
7350
|
const conditions = [eq14(gscSearchData.projectId, project.id)];
|
|
7316
|
-
if (startDate) conditions.push(
|
|
7317
|
-
else if (cutoffDate) conditions.push(
|
|
7318
|
-
if (endDate) conditions.push(
|
|
7319
|
-
if (query) conditions.push(
|
|
7320
|
-
if (page) conditions.push(
|
|
7351
|
+
if (startDate) conditions.push(sql3`${gscSearchData.date} >= ${startDate}`);
|
|
7352
|
+
else if (cutoffDate) conditions.push(sql3`${gscSearchData.date} >= ${cutoffDate}`);
|
|
7353
|
+
if (endDate) conditions.push(sql3`${gscSearchData.date} <= ${endDate}`);
|
|
7354
|
+
if (query) conditions.push(sql3`${gscSearchData.query} LIKE ${"%" + query + "%"}`);
|
|
7355
|
+
if (page) conditions.push(sql3`${gscSearchData.page} LIKE ${"%" + page + "%"}`);
|
|
7321
7356
|
const rows = app.db.select().from(gscSearchData).where(and3(...conditions)).orderBy(desc5(gscSearchData.date)).limit(parseInt(limit ?? "500", 10)).all();
|
|
7322
7357
|
return rows.map((r) => ({
|
|
7323
7358
|
date: r.date,
|
|
@@ -8543,7 +8578,7 @@ async function cdpRoutes(app, opts) {
|
|
|
8543
8578
|
|
|
8544
8579
|
// ../api-routes/src/ga.ts
|
|
8545
8580
|
import crypto16 from "crypto";
|
|
8546
|
-
import { eq as eq17, desc as desc7, and as and6, sql as
|
|
8581
|
+
import { eq as eq17, desc as desc7, and as and6, sql as sql4 } from "drizzle-orm";
|
|
8547
8582
|
function gaLog(level, action, ctx) {
|
|
8548
8583
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
|
|
8549
8584
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
@@ -8785,8 +8820,8 @@ async function ga4Routes(app, opts) {
|
|
|
8785
8820
|
tx.delete(gaTrafficSnapshots).where(
|
|
8786
8821
|
and6(
|
|
8787
8822
|
eq17(gaTrafficSnapshots.projectId, project.id),
|
|
8788
|
-
|
|
8789
|
-
|
|
8823
|
+
sql4`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
|
|
8824
|
+
sql4`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
|
|
8790
8825
|
)
|
|
8791
8826
|
).run();
|
|
8792
8827
|
for (const row of rows) {
|
|
@@ -8807,8 +8842,8 @@ async function ga4Routes(app, opts) {
|
|
|
8807
8842
|
tx.delete(gaAiReferrals).where(
|
|
8808
8843
|
and6(
|
|
8809
8844
|
eq17(gaAiReferrals.projectId, project.id),
|
|
8810
|
-
|
|
8811
|
-
|
|
8845
|
+
sql4`${gaAiReferrals.date} >= ${summary.periodStart}`,
|
|
8846
|
+
sql4`${gaAiReferrals.date} <= ${summary.periodEnd}`
|
|
8812
8847
|
)
|
|
8813
8848
|
).run();
|
|
8814
8849
|
for (const row of aiReferrals) {
|
|
@@ -8830,8 +8865,8 @@ async function ga4Routes(app, opts) {
|
|
|
8830
8865
|
tx.delete(gaSocialReferrals).where(
|
|
8831
8866
|
and6(
|
|
8832
8867
|
eq17(gaSocialReferrals.projectId, project.id),
|
|
8833
|
-
|
|
8834
|
-
|
|
8868
|
+
sql4`${gaSocialReferrals.date} >= ${summary.periodStart}`,
|
|
8869
|
+
sql4`${gaSocialReferrals.date} <= ${summary.periodEnd}`
|
|
8835
8870
|
)
|
|
8836
8871
|
).run();
|
|
8837
8872
|
for (const row of socialReferrals) {
|
|
@@ -8900,15 +8935,15 @@ async function ga4Routes(app, opts) {
|
|
|
8900
8935
|
const cutoff = windowCutoff(window);
|
|
8901
8936
|
const cutoffDate = cutoff?.slice(0, 10) ?? null;
|
|
8902
8937
|
const snapshotConditions = [eq17(gaTrafficSnapshots.projectId, project.id)];
|
|
8903
|
-
if (cutoffDate) snapshotConditions.push(
|
|
8938
|
+
if (cutoffDate) snapshotConditions.push(sql4`${gaTrafficSnapshots.date} >= ${cutoffDate}`);
|
|
8904
8939
|
const aiConditions = [eq17(gaAiReferrals.projectId, project.id)];
|
|
8905
|
-
if (cutoffDate) aiConditions.push(
|
|
8940
|
+
if (cutoffDate) aiConditions.push(sql4`${gaAiReferrals.date} >= ${cutoffDate}`);
|
|
8906
8941
|
const socialConditions = [eq17(gaSocialReferrals.projectId, project.id)];
|
|
8907
|
-
if (cutoffDate) socialConditions.push(
|
|
8942
|
+
if (cutoffDate) socialConditions.push(sql4`${gaSocialReferrals.date} >= ${cutoffDate}`);
|
|
8908
8943
|
const summaryRow = cutoffDate ? app.db.select({
|
|
8909
|
-
totalSessions:
|
|
8910
|
-
totalOrganicSessions:
|
|
8911
|
-
totalUsers:
|
|
8944
|
+
totalSessions: sql4`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
|
|
8945
|
+
totalOrganicSessions: sql4`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
|
|
8946
|
+
totalUsers: sql4`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
|
|
8912
8947
|
}).from(gaTrafficSnapshots).where(and6(...snapshotConditions)).get() : app.db.select({
|
|
8913
8948
|
totalSessions: gaTrafficSummaries.totalSessions,
|
|
8914
8949
|
totalOrganicSessions: gaTrafficSummaries.totalOrganicSessions,
|
|
@@ -8920,27 +8955,27 @@ async function ga4Routes(app, opts) {
|
|
|
8920
8955
|
}).from(gaTrafficSummaries).where(eq17(gaTrafficSummaries.projectId, project.id)).get();
|
|
8921
8956
|
const rows = app.db.select({
|
|
8922
8957
|
landingPage: gaTrafficSnapshots.landingPage,
|
|
8923
|
-
sessions:
|
|
8924
|
-
organicSessions:
|
|
8925
|
-
users:
|
|
8926
|
-
}).from(gaTrafficSnapshots).where(and6(...snapshotConditions)).groupBy(gaTrafficSnapshots.landingPage).orderBy(
|
|
8958
|
+
sessions: sql4`SUM(${gaTrafficSnapshots.sessions})`,
|
|
8959
|
+
organicSessions: sql4`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
8960
|
+
users: sql4`SUM(${gaTrafficSnapshots.users})`
|
|
8961
|
+
}).from(gaTrafficSnapshots).where(and6(...snapshotConditions)).groupBy(gaTrafficSnapshots.landingPage).orderBy(sql4`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
|
|
8927
8962
|
const aiReferrals = app.db.select({
|
|
8928
8963
|
source: gaAiReferrals.source,
|
|
8929
8964
|
medium: gaAiReferrals.medium,
|
|
8930
8965
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
8931
|
-
sessions:
|
|
8932
|
-
users:
|
|
8933
|
-
}).from(gaAiReferrals).where(and6(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).orderBy(
|
|
8966
|
+
sessions: sql4`SUM(${gaAiReferrals.sessions})`,
|
|
8967
|
+
users: sql4`SUM(${gaAiReferrals.users})`
|
|
8968
|
+
}).from(gaAiReferrals).where(and6(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).orderBy(sql4`SUM(${gaAiReferrals.sessions}) DESC`).all();
|
|
8934
8969
|
const aiDeduped = app.db.select({
|
|
8935
|
-
sessions:
|
|
8936
|
-
users:
|
|
8970
|
+
sessions: sql4`SUM(max_sessions)`,
|
|
8971
|
+
users: sql4`SUM(max_users)`
|
|
8937
8972
|
}).from(
|
|
8938
|
-
|
|
8973
|
+
sql4`(
|
|
8939
8974
|
SELECT date, source, medium,
|
|
8940
8975
|
MAX(sessions) AS max_sessions,
|
|
8941
8976
|
MAX(users) AS max_users
|
|
8942
8977
|
FROM ga_ai_referrals
|
|
8943
|
-
WHERE project_id = ${project.id}${cutoffDate ?
|
|
8978
|
+
WHERE project_id = ${project.id}${cutoffDate ? sql4` AND date >= ${cutoffDate}` : sql4``}
|
|
8944
8979
|
GROUP BY date, source, medium
|
|
8945
8980
|
)`
|
|
8946
8981
|
).get();
|
|
@@ -8948,12 +8983,12 @@ async function ga4Routes(app, opts) {
|
|
|
8948
8983
|
source: gaSocialReferrals.source,
|
|
8949
8984
|
medium: gaSocialReferrals.medium,
|
|
8950
8985
|
channelGroup: gaSocialReferrals.channelGroup,
|
|
8951
|
-
sessions:
|
|
8952
|
-
users:
|
|
8953
|
-
}).from(gaSocialReferrals).where(and6(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(
|
|
8986
|
+
sessions: sql4`SUM(${gaSocialReferrals.sessions})`,
|
|
8987
|
+
users: sql4`SUM(${gaSocialReferrals.users})`
|
|
8988
|
+
}).from(gaSocialReferrals).where(and6(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql4`SUM(${gaSocialReferrals.sessions}) DESC`).all();
|
|
8954
8989
|
const socialTotals = app.db.select({
|
|
8955
|
-
sessions:
|
|
8956
|
-
users:
|
|
8990
|
+
sessions: sql4`SUM(${gaSocialReferrals.sessions})`,
|
|
8991
|
+
users: sql4`SUM(${gaSocialReferrals.users})`
|
|
8957
8992
|
}).from(gaSocialReferrals).where(and6(...socialConditions)).get();
|
|
8958
8993
|
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq17(gaTrafficSummaries.projectId, project.id)).orderBy(desc7(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
8959
8994
|
const total = summaryRow?.totalSessions ?? 0;
|
|
@@ -9003,7 +9038,7 @@ async function ga4Routes(app, opts) {
|
|
|
9003
9038
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
9004
9039
|
const cutoffDate = windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null;
|
|
9005
9040
|
const conditions = [eq17(gaAiReferrals.projectId, project.id)];
|
|
9006
|
-
if (cutoffDate) conditions.push(
|
|
9041
|
+
if (cutoffDate) conditions.push(sql4`${gaAiReferrals.date} >= ${cutoffDate}`);
|
|
9007
9042
|
const rows = app.db.select({
|
|
9008
9043
|
date: gaAiReferrals.date,
|
|
9009
9044
|
source: gaAiReferrals.source,
|
|
@@ -9019,7 +9054,7 @@ async function ga4Routes(app, opts) {
|
|
|
9019
9054
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
9020
9055
|
const cutoffDate = windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null;
|
|
9021
9056
|
const conditions = [eq17(gaSocialReferrals.projectId, project.id)];
|
|
9022
|
-
if (cutoffDate) conditions.push(
|
|
9057
|
+
if (cutoffDate) conditions.push(sql4`${gaSocialReferrals.date} >= ${cutoffDate}`);
|
|
9023
9058
|
const rows = app.db.select({
|
|
9024
9059
|
date: gaSocialReferrals.date,
|
|
9025
9060
|
source: gaSocialReferrals.source,
|
|
@@ -9040,10 +9075,10 @@ async function ga4Routes(app, opts) {
|
|
|
9040
9075
|
d.setDate(d.getDate() - n);
|
|
9041
9076
|
return fmt(d);
|
|
9042
9077
|
};
|
|
9043
|
-
const sumSocial = (from, to) => app.db.select({ sessions:
|
|
9078
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql4`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and6(
|
|
9044
9079
|
eq17(gaSocialReferrals.projectId, project.id),
|
|
9045
|
-
|
|
9046
|
-
|
|
9080
|
+
sql4`${gaSocialReferrals.date} >= ${from}`,
|
|
9081
|
+
sql4`${gaSocialReferrals.date} < ${to}`
|
|
9047
9082
|
)).get();
|
|
9048
9083
|
const current7d = sumSocial(daysAgo2(7), fmt(today));
|
|
9049
9084
|
const prev7d = sumSocial(daysAgo2(14), daysAgo2(7));
|
|
@@ -9052,19 +9087,19 @@ async function ga4Routes(app, opts) {
|
|
|
9052
9087
|
const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
|
|
9053
9088
|
const sourceCurrent = app.db.select({
|
|
9054
9089
|
source: gaSocialReferrals.source,
|
|
9055
|
-
sessions:
|
|
9090
|
+
sessions: sql4`SUM(${gaSocialReferrals.sessions})`
|
|
9056
9091
|
}).from(gaSocialReferrals).where(and6(
|
|
9057
9092
|
eq17(gaSocialReferrals.projectId, project.id),
|
|
9058
|
-
|
|
9059
|
-
|
|
9093
|
+
sql4`${gaSocialReferrals.date} >= ${daysAgo2(7)}`,
|
|
9094
|
+
sql4`${gaSocialReferrals.date} < ${fmt(today)}`
|
|
9060
9095
|
)).groupBy(gaSocialReferrals.source).all();
|
|
9061
9096
|
const sourcePrev = app.db.select({
|
|
9062
9097
|
source: gaSocialReferrals.source,
|
|
9063
|
-
sessions:
|
|
9098
|
+
sessions: sql4`SUM(${gaSocialReferrals.sessions})`
|
|
9064
9099
|
}).from(gaSocialReferrals).where(and6(
|
|
9065
9100
|
eq17(gaSocialReferrals.projectId, project.id),
|
|
9066
|
-
|
|
9067
|
-
|
|
9101
|
+
sql4`${gaSocialReferrals.date} >= ${daysAgo2(14)}`,
|
|
9102
|
+
sql4`${gaSocialReferrals.date} < ${daysAgo2(7)}`
|
|
9068
9103
|
)).groupBy(gaSocialReferrals.source).all();
|
|
9069
9104
|
const prevMap = new Map(sourcePrev.map((r) => [r.source, r.sessions]));
|
|
9070
9105
|
let biggestMover = null;
|
|
@@ -9103,15 +9138,15 @@ async function ga4Routes(app, opts) {
|
|
|
9103
9138
|
return fmt(d);
|
|
9104
9139
|
};
|
|
9105
9140
|
const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
|
|
9106
|
-
const sumTotal = (from, to) => app.db.select({ sessions:
|
|
9107
|
-
const sumOrganic = (from, to) => app.db.select({ sessions:
|
|
9108
|
-
const sumAi = (from, to) => app.db.select({ sessions:
|
|
9141
|
+
const sumTotal = (from, to) => app.db.select({ sessions: sql4`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and6(eq17(gaTrafficSnapshots.projectId, project.id), sql4`${gaTrafficSnapshots.date} >= ${from}`, sql4`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
9142
|
+
const sumOrganic = (from, to) => app.db.select({ sessions: sql4`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and6(eq17(gaTrafficSnapshots.projectId, project.id), sql4`${gaTrafficSnapshots.date} >= ${from}`, sql4`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
9143
|
+
const sumAi = (from, to) => app.db.select({ sessions: sql4`COALESCE(SUM(max_sessions), 0)` }).from(sql4`(
|
|
9109
9144
|
SELECT date, source, medium, MAX(sessions) AS max_sessions
|
|
9110
9145
|
FROM ga_ai_referrals
|
|
9111
9146
|
WHERE project_id = ${project.id} AND date >= ${from} AND date < ${to}
|
|
9112
9147
|
GROUP BY date, source, medium
|
|
9113
9148
|
)`).get();
|
|
9114
|
-
const sumSocial = (from, to) => app.db.select({ sessions:
|
|
9149
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql4`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and6(eq17(gaSocialReferrals.projectId, project.id), sql4`${gaSocialReferrals.date} >= ${from}`, sql4`${gaSocialReferrals.date} < ${to}`)).get();
|
|
9115
9150
|
const todayStr = fmt(today);
|
|
9116
9151
|
const buildTrend = (sum) => {
|
|
9117
9152
|
const c7 = sum(daysAgo2(7), todayStr)?.sessions ?? 0;
|
|
@@ -9120,18 +9155,18 @@ async function ga4Routes(app, opts) {
|
|
|
9120
9155
|
const p30 = sum(daysAgo2(60), daysAgo2(30))?.sessions ?? 0;
|
|
9121
9156
|
return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: pct(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: pct(c30, p30) };
|
|
9122
9157
|
};
|
|
9123
|
-
const aiSourceCurrent = app.db.select({ source:
|
|
9158
|
+
const aiSourceCurrent = app.db.select({ source: sql4`source`, sessions: sql4`COALESCE(SUM(max_sessions), 0)` }).from(sql4`(
|
|
9124
9159
|
SELECT date, source, medium, MAX(sessions) AS max_sessions
|
|
9125
9160
|
FROM ga_ai_referrals
|
|
9126
9161
|
WHERE project_id = ${project.id} AND date >= ${daysAgo2(7)} AND date < ${todayStr}
|
|
9127
9162
|
GROUP BY date, source, medium
|
|
9128
|
-
)`).groupBy(
|
|
9129
|
-
const aiSourcePrev = app.db.select({ source:
|
|
9163
|
+
)`).groupBy(sql4`source`).all();
|
|
9164
|
+
const aiSourcePrev = app.db.select({ source: sql4`source`, sessions: sql4`COALESCE(SUM(max_sessions), 0)` }).from(sql4`(
|
|
9130
9165
|
SELECT date, source, medium, MAX(sessions) AS max_sessions
|
|
9131
9166
|
FROM ga_ai_referrals
|
|
9132
9167
|
WHERE project_id = ${project.id} AND date >= ${daysAgo2(14)} AND date < ${daysAgo2(7)}
|
|
9133
9168
|
GROUP BY date, source, medium
|
|
9134
|
-
)`).groupBy(
|
|
9169
|
+
)`).groupBy(sql4`source`).all();
|
|
9135
9170
|
const findBiggestMover = (current, prev) => {
|
|
9136
9171
|
const prevMap = new Map(prev.map((r) => [r.source, r.sessions]));
|
|
9137
9172
|
let mover = null;
|
|
@@ -9146,8 +9181,8 @@ async function ga4Routes(app, opts) {
|
|
|
9146
9181
|
}
|
|
9147
9182
|
return mover;
|
|
9148
9183
|
};
|
|
9149
|
-
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions:
|
|
9150
|
-
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions:
|
|
9184
|
+
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql4`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and6(eq17(gaSocialReferrals.projectId, project.id), sql4`${gaSocialReferrals.date} >= ${daysAgo2(7)}`, sql4`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
|
|
9185
|
+
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql4`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and6(eq17(gaSocialReferrals.projectId, project.id), sql4`${gaSocialReferrals.date} >= ${daysAgo2(14)}`, sql4`${gaSocialReferrals.date} < ${daysAgo2(7)}`)).groupBy(gaSocialReferrals.source).all();
|
|
9151
9186
|
return {
|
|
9152
9187
|
total: buildTrend(sumTotal),
|
|
9153
9188
|
organic: buildTrend(sumOrganic),
|
|
@@ -9162,12 +9197,12 @@ async function ga4Routes(app, opts) {
|
|
|
9162
9197
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
9163
9198
|
const cutoffDate = windowCutoff(parseWindow(request.query.window))?.slice(0, 10) ?? null;
|
|
9164
9199
|
const conditions = [eq17(gaTrafficSnapshots.projectId, project.id)];
|
|
9165
|
-
if (cutoffDate) conditions.push(
|
|
9200
|
+
if (cutoffDate) conditions.push(sql4`${gaTrafficSnapshots.date} >= ${cutoffDate}`);
|
|
9166
9201
|
const rows = app.db.select({
|
|
9167
9202
|
date: gaTrafficSnapshots.date,
|
|
9168
|
-
sessions:
|
|
9169
|
-
organicSessions:
|
|
9170
|
-
users:
|
|
9203
|
+
sessions: sql4`SUM(${gaTrafficSnapshots.sessions})`,
|
|
9204
|
+
organicSessions: sql4`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
9205
|
+
users: sql4`SUM(${gaTrafficSnapshots.users})`
|
|
9171
9206
|
}).from(gaTrafficSnapshots).where(and6(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
|
|
9172
9207
|
return rows.map((r) => ({
|
|
9173
9208
|
date: r.date,
|
|
@@ -9181,10 +9216,10 @@ async function ga4Routes(app, opts) {
|
|
|
9181
9216
|
requireGa4Connection(opts, project.name, project.canonicalDomain);
|
|
9182
9217
|
const trafficPages = app.db.select({
|
|
9183
9218
|
landingPage: gaTrafficSnapshots.landingPage,
|
|
9184
|
-
sessions:
|
|
9185
|
-
organicSessions:
|
|
9186
|
-
users:
|
|
9187
|
-
}).from(gaTrafficSnapshots).where(eq17(gaTrafficSnapshots.projectId, project.id)).groupBy(gaTrafficSnapshots.landingPage).orderBy(
|
|
9219
|
+
sessions: sql4`SUM(${gaTrafficSnapshots.sessions})`,
|
|
9220
|
+
organicSessions: sql4`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
9221
|
+
users: sql4`SUM(${gaTrafficSnapshots.users})`
|
|
9222
|
+
}).from(gaTrafficSnapshots).where(eq17(gaTrafficSnapshots.projectId, project.id)).groupBy(gaTrafficSnapshots.landingPage).orderBy(sql4`SUM(${gaTrafficSnapshots.sessions}) DESC`).all();
|
|
9188
9223
|
return {
|
|
9189
9224
|
pages: trafficPages.map((r) => ({
|
|
9190
9225
|
landingPage: r.landingPage,
|
|
@@ -13457,7 +13492,7 @@ import crypto18 from "crypto";
|
|
|
13457
13492
|
import fs4 from "fs";
|
|
13458
13493
|
import path5 from "path";
|
|
13459
13494
|
import os4 from "os";
|
|
13460
|
-
import { and as and7, eq as eq18, inArray as inArray3, sql as
|
|
13495
|
+
import { and as and7, eq as eq18, inArray as inArray3, sql as sql5 } from "drizzle-orm";
|
|
13461
13496
|
|
|
13462
13497
|
// src/citation-utils.ts
|
|
13463
13498
|
function domainMatches(domain, canonicalDomain) {
|
|
@@ -13971,7 +14006,7 @@ var JobRunner = class {
|
|
|
13971
14006
|
updatedAt: now
|
|
13972
14007
|
}).onConflictDoUpdate({
|
|
13973
14008
|
target: [usageCounters.scope, usageCounters.period, usageCounters.metric],
|
|
13974
|
-
set: { count:
|
|
14009
|
+
set: { count: sql5`${usageCounters.count} + ${count}`, updatedAt: now }
|
|
13975
14010
|
}).run();
|
|
13976
14011
|
}
|
|
13977
14012
|
flushProviderUsage(projectId, providerDispatchCounts) {
|
|
@@ -14024,7 +14059,7 @@ function getCurrentUsageDay() {
|
|
|
14024
14059
|
|
|
14025
14060
|
// src/gsc-sync.ts
|
|
14026
14061
|
import crypto19 from "crypto";
|
|
14027
|
-
import { eq as eq19, and as and8, sql as
|
|
14062
|
+
import { eq as eq19, and as and8, sql as sql6 } from "drizzle-orm";
|
|
14028
14063
|
var log2 = createLogger("GscSync");
|
|
14029
14064
|
function formatDate2(d) {
|
|
14030
14065
|
return d.toISOString().split("T")[0];
|
|
@@ -14078,8 +14113,8 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
14078
14113
|
db.delete(gscSearchData).where(
|
|
14079
14114
|
and8(
|
|
14080
14115
|
eq19(gscSearchData.projectId, projectId),
|
|
14081
|
-
|
|
14082
|
-
|
|
14116
|
+
sql6`${gscSearchData.date} >= ${startDate}`,
|
|
14117
|
+
sql6`${gscSearchData.date} <= ${endDate}`
|
|
14083
14118
|
)
|
|
14084
14119
|
).run();
|
|
14085
14120
|
const batchSize = 500;
|
|
@@ -15023,7 +15058,7 @@ import { Type as Type2 } from "@sinclair/typebox";
|
|
|
15023
15058
|
|
|
15024
15059
|
// src/agent/memory-store.ts
|
|
15025
15060
|
import crypto22 from "crypto";
|
|
15026
|
-
import { and as and11, desc as desc9, eq as eq23, like, sql as
|
|
15061
|
+
import { and as and11, desc as desc9, eq as eq23, like, sql as sql7 } from "drizzle-orm";
|
|
15027
15062
|
var COMPACTION_KEY_PREFIX = "compaction:";
|
|
15028
15063
|
var COMPACTION_NOTES_PER_SESSION = 3;
|
|
15029
15064
|
function rowToDto(row) {
|
|
@@ -15109,7 +15144,7 @@ function writeCompactionNote(db, args) {
|
|
|
15109
15144
|
).orderBy(desc9(agentMemory.updatedAt)).all();
|
|
15110
15145
|
const stale = existing.slice(COMPACTION_NOTES_PER_SESSION).map((r) => r.id);
|
|
15111
15146
|
if (stale.length > 0) {
|
|
15112
|
-
tx.delete(agentMemory).where(
|
|
15147
|
+
tx.delete(agentMemory).where(sql7`${agentMemory.id} IN (${sql7.join(stale.map((s) => sql7`${s}`), sql7`, `)})`).run();
|
|
15113
15148
|
}
|
|
15114
15149
|
const row = tx.select().from(agentMemory).where(and11(eq23(agentMemory.projectId, args.projectId), eq23(agentMemory.key, key))).get();
|
|
15115
15150
|
if (row) inserted = rowToDto(row);
|
|
@@ -16402,7 +16437,7 @@ var ApiClient = class {
|
|
|
16402
16437
|
const msg = errorObj?.message ? String(errorObj.message) : `HTTP ${res.status}: ${res.statusText}`;
|
|
16403
16438
|
const code = errorObj?.code ? String(errorObj.code) : "API_ERROR";
|
|
16404
16439
|
const exitCode = res.status >= 500 ? EXIT_SYSTEM_ERROR : EXIT_USER_ERROR;
|
|
16405
|
-
throw new CliError({ code, message: msg, exitCode });
|
|
16440
|
+
throw new CliError({ code, message: msg, exitCode, details: { httpStatus: res.status } });
|
|
16406
16441
|
}
|
|
16407
16442
|
if (res.status === 204) {
|
|
16408
16443
|
return void 0;
|
|
@@ -16492,7 +16527,7 @@ var ApiClient = class {
|
|
|
16492
16527
|
const msg = errorObj?.message ? String(errorObj.message) : `HTTP ${res.status}: ${res.statusText}`;
|
|
16493
16528
|
const code = errorObj?.code ? String(errorObj.code) : "API_ERROR";
|
|
16494
16529
|
const exitCode = res.status >= 500 ? EXIT_SYSTEM_ERROR : EXIT_USER_ERROR;
|
|
16495
|
-
throw new CliError({ code, message: msg, exitCode });
|
|
16530
|
+
throw new CliError({ code, message: msg, exitCode, details: { httpStatus: res.status } });
|
|
16496
16531
|
}
|
|
16497
16532
|
return res;
|
|
16498
16533
|
}
|
|
@@ -16533,6 +16568,9 @@ var ApiClient = class {
|
|
|
16533
16568
|
const query = limit != null ? `?limit=${encodeURIComponent(String(limit))}` : "";
|
|
16534
16569
|
return this.request("GET", `/projects/${encodeURIComponent(project)}/runs${query}`);
|
|
16535
16570
|
}
|
|
16571
|
+
async getLatestRun(project) {
|
|
16572
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/runs/latest`);
|
|
16573
|
+
}
|
|
16536
16574
|
async getRun(id) {
|
|
16537
16575
|
return this.request("GET", `/runs/${encodeURIComponent(id)}`);
|
|
16538
16576
|
}
|
|
@@ -18422,6 +18460,7 @@ export {
|
|
|
18422
18460
|
EXIT_SYSTEM_ERROR,
|
|
18423
18461
|
CliError,
|
|
18424
18462
|
usageError,
|
|
18463
|
+
isEndpointMissing,
|
|
18425
18464
|
printCliError,
|
|
18426
18465
|
providerQuotaPolicySchema,
|
|
18427
18466
|
ProviderNames,
|