@ainyc/canonry 1.45.0 → 1.45.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/assets/{index-BsF7MVAu.js → index-Dh9YyROK.js} +24 -24
- package/assets/index.html +1 -1
- package/dist/{chunk-SVPQUYTG.js → chunk-HO22LHTY.js} +47 -17
- package/dist/{chunk-B4EP44AR.js → chunk-WNOUK4KA.js} +336 -199
- package/dist/cli.js +32 -32
- package/dist/index.js +2 -2
- package/dist/{intelligence-service-TXWOESFH.js → intelligence-service-ZISLIU4S.js} +1 -1
- package/package.json +5 -5
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
runs,
|
|
24
24
|
schedules,
|
|
25
25
|
usageCounters
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-HO22LHTY.js";
|
|
27
27
|
|
|
28
28
|
// src/config.ts
|
|
29
29
|
import fs from "fs";
|
|
@@ -268,7 +268,7 @@ import crypto22 from "crypto";
|
|
|
268
268
|
import fs5 from "fs";
|
|
269
269
|
import path6 from "path";
|
|
270
270
|
import { fileURLToPath } from "url";
|
|
271
|
-
import { eq as eq23 } from "drizzle-orm";
|
|
271
|
+
import { eq as eq23, sql as sql6 } from "drizzle-orm";
|
|
272
272
|
import Fastify from "fastify";
|
|
273
273
|
|
|
274
274
|
// ../contracts/src/config-schema.ts
|
|
@@ -817,7 +817,14 @@ var wordpressDiffDtoSchema = z7.object({
|
|
|
817
817
|
import { z as z8 } from "zod";
|
|
818
818
|
var runStatusSchema = z8.enum(["queued", "running", "completed", "partial", "failed", "cancelled"]);
|
|
819
819
|
var RunStatuses = runStatusSchema.enum;
|
|
820
|
-
var runKindSchema = z8.enum([
|
|
820
|
+
var runKindSchema = z8.enum([
|
|
821
|
+
"answer-visibility",
|
|
822
|
+
"site-audit",
|
|
823
|
+
"gsc-sync",
|
|
824
|
+
"inspect-sitemap",
|
|
825
|
+
"ga-sync",
|
|
826
|
+
"bing-inspect"
|
|
827
|
+
]);
|
|
821
828
|
var RunKinds = runKindSchema.enum;
|
|
822
829
|
var runTriggerSchema = z8.enum(["manual", "scheduled", "config-apply"]);
|
|
823
830
|
var RunTriggers = runTriggerSchema.enum;
|
|
@@ -6171,7 +6178,14 @@ function validateDate(date, label) {
|
|
|
6171
6178
|
}
|
|
6172
6179
|
}
|
|
6173
6180
|
function gscClientLog(level, action, ctx) {
|
|
6174
|
-
const entry = {
|
|
6181
|
+
const entry = {
|
|
6182
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6183
|
+
level,
|
|
6184
|
+
module: "GscClient",
|
|
6185
|
+
action,
|
|
6186
|
+
...ctx
|
|
6187
|
+
};
|
|
6188
|
+
if (entry.accessToken) entry.accessToken = "***";
|
|
6175
6189
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
6176
6190
|
stream.write(JSON.stringify(entry) + "\n");
|
|
6177
6191
|
}
|
|
@@ -6348,7 +6362,15 @@ function validateScope(scope) {
|
|
|
6348
6362
|
}
|
|
6349
6363
|
}
|
|
6350
6364
|
function ga4Log(level, action, ctx) {
|
|
6351
|
-
const entry = {
|
|
6365
|
+
const entry = {
|
|
6366
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6367
|
+
level,
|
|
6368
|
+
module: "GA4Client",
|
|
6369
|
+
action,
|
|
6370
|
+
...ctx
|
|
6371
|
+
};
|
|
6372
|
+
if (entry.accessToken) entry.accessToken = "***";
|
|
6373
|
+
if (entry.privateKey) entry.privateKey = "***";
|
|
6352
6374
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
6353
6375
|
stream.write(JSON.stringify(entry) + "\n");
|
|
6354
6376
|
}
|
|
@@ -7542,7 +7564,15 @@ function validateUrls(urls) {
|
|
|
7542
7564
|
}
|
|
7543
7565
|
}
|
|
7544
7566
|
function bingClientLog(level, action, ctx) {
|
|
7545
|
-
const entry = {
|
|
7567
|
+
const entry = {
|
|
7568
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7569
|
+
level,
|
|
7570
|
+
module: "BingClient",
|
|
7571
|
+
action,
|
|
7572
|
+
...ctx
|
|
7573
|
+
};
|
|
7574
|
+
if (entry.apiKey) entry.apiKey = "***";
|
|
7575
|
+
if (entry.apikey) entry.apikey = "***";
|
|
7546
7576
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
7547
7577
|
stream.write(JSON.stringify(entry) + "\n");
|
|
7548
7578
|
}
|
|
@@ -7793,6 +7823,7 @@ async function bingRoutes(app, opts) {
|
|
|
7793
7823
|
const notIndexedUrls = [];
|
|
7794
7824
|
const unknownUrls = [];
|
|
7795
7825
|
let lastInspectedAt = null;
|
|
7826
|
+
let snapshotRunId = null;
|
|
7796
7827
|
for (const [, row] of latestByUrl) {
|
|
7797
7828
|
if (row.inIndex === 1) {
|
|
7798
7829
|
indexedUrls.push(row);
|
|
@@ -7803,6 +7834,7 @@ async function bingRoutes(app, opts) {
|
|
|
7803
7834
|
}
|
|
7804
7835
|
if (!lastInspectedAt || row.inspectedAt > lastInspectedAt) {
|
|
7805
7836
|
lastInspectedAt = row.inspectedAt;
|
|
7837
|
+
snapshotRunId = row.syncRunId ?? null;
|
|
7806
7838
|
}
|
|
7807
7839
|
}
|
|
7808
7840
|
const indexed = indexedUrls.length;
|
|
@@ -7827,6 +7859,7 @@ async function bingRoutes(app, opts) {
|
|
|
7827
7859
|
app.db.insert(bingCoverageSnapshots).values({
|
|
7828
7860
|
id: crypto15.randomUUID(),
|
|
7829
7861
|
projectId: project.id,
|
|
7862
|
+
syncRunId: snapshotRunId,
|
|
7830
7863
|
date: snapshotDate,
|
|
7831
7864
|
indexed,
|
|
7832
7865
|
notIndexed,
|
|
@@ -7834,7 +7867,7 @@ async function bingRoutes(app, opts) {
|
|
|
7834
7867
|
createdAt: now
|
|
7835
7868
|
}).onConflictDoUpdate({
|
|
7836
7869
|
target: [bingCoverageSnapshots.projectId, bingCoverageSnapshots.date],
|
|
7837
|
-
set: { indexed, notIndexed, unknown, createdAt: now }
|
|
7870
|
+
set: { indexed, notIndexed, unknown, createdAt: now, syncRunId: snapshotRunId }
|
|
7838
7871
|
}).run();
|
|
7839
7872
|
}
|
|
7840
7873
|
return {
|
|
@@ -7900,9 +7933,19 @@ async function bingRoutes(app, opts) {
|
|
|
7900
7933
|
const err = validationError("url is required");
|
|
7901
7934
|
return reply.status(err.statusCode).send(err.toJSON());
|
|
7902
7935
|
}
|
|
7903
|
-
|
|
7936
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7937
|
+
const runId = crypto15.randomUUID();
|
|
7938
|
+
app.db.insert(runs).values({
|
|
7939
|
+
id: runId,
|
|
7940
|
+
projectId: project.id,
|
|
7941
|
+
kind: RunKinds["bing-inspect"],
|
|
7942
|
+
status: RunStatuses.running,
|
|
7943
|
+
trigger: RunTriggers.manual,
|
|
7944
|
+
startedAt,
|
|
7945
|
+
createdAt: startedAt
|
|
7946
|
+
}).run();
|
|
7904
7947
|
try {
|
|
7905
|
-
result = await getUrlInfo(conn.apiKey, conn.siteUrl, url);
|
|
7948
|
+
const result = await getUrlInfo(conn.apiKey, conn.siteUrl, url);
|
|
7906
7949
|
bingLog("info", "inspect-url.result", {
|
|
7907
7950
|
domain: project.canonicalDomain,
|
|
7908
7951
|
url,
|
|
@@ -7911,49 +7954,52 @@ async function bingRoutes(app, opts) {
|
|
|
7911
7954
|
documentSize: result.DocumentSize ?? null,
|
|
7912
7955
|
lastCrawledDate: result.LastCrawledDate ?? null
|
|
7913
7956
|
});
|
|
7957
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7958
|
+
const id = crypto15.randomUUID();
|
|
7959
|
+
const httpCode = result.HttpStatus ?? result.HttpCode ?? null;
|
|
7960
|
+
let derivedInIndex = null;
|
|
7961
|
+
if (result.InIndex != null) {
|
|
7962
|
+
derivedInIndex = result.InIndex;
|
|
7963
|
+
} else if (result.DocumentSize != null && result.DocumentSize > 0) {
|
|
7964
|
+
derivedInIndex = true;
|
|
7965
|
+
}
|
|
7966
|
+
const lastCrawledDate = parseBingDate(result.LastCrawledDate);
|
|
7967
|
+
const inIndexDate = parseBingDate(result.InIndexDate);
|
|
7968
|
+
const discoveryDate = parseBingDate(result.DiscoveryDate);
|
|
7969
|
+
app.db.insert(bingUrlInspections).values({
|
|
7970
|
+
id,
|
|
7971
|
+
projectId: project.id,
|
|
7972
|
+
url,
|
|
7973
|
+
httpCode,
|
|
7974
|
+
inIndex: derivedInIndex === true ? 1 : derivedInIndex === false ? 0 : null,
|
|
7975
|
+
lastCrawledDate,
|
|
7976
|
+
inIndexDate,
|
|
7977
|
+
inspectedAt: now,
|
|
7978
|
+
syncRunId: runId,
|
|
7979
|
+
createdAt: now,
|
|
7980
|
+
documentSize: result.DocumentSize ?? null,
|
|
7981
|
+
anchorCount: result.AnchorCount ?? null,
|
|
7982
|
+
discoveryDate
|
|
7983
|
+
}).run();
|
|
7984
|
+
app.db.update(runs).set({ status: RunStatuses.completed, finishedAt: now }).where(eq15(runs.id, runId)).run();
|
|
7985
|
+
return {
|
|
7986
|
+
id,
|
|
7987
|
+
url,
|
|
7988
|
+
httpCode,
|
|
7989
|
+
inIndex: derivedInIndex,
|
|
7990
|
+
lastCrawledDate,
|
|
7991
|
+
inIndexDate,
|
|
7992
|
+
inspectedAt: now,
|
|
7993
|
+
documentSize: result.DocumentSize ?? null,
|
|
7994
|
+
anchorCount: result.AnchorCount ?? null,
|
|
7995
|
+
discoveryDate
|
|
7996
|
+
};
|
|
7914
7997
|
} catch (e) {
|
|
7915
7998
|
const msg = e instanceof Error ? e.message : String(e);
|
|
7916
7999
|
bingLog("error", "inspect-url.failed", { domain: project.canonicalDomain, url, error: msg });
|
|
8000
|
+
app.db.update(runs).set({ status: RunStatuses.failed, error: msg, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq15(runs.id, runId)).run();
|
|
7917
8001
|
throw e;
|
|
7918
8002
|
}
|
|
7919
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7920
|
-
const id = crypto15.randomUUID();
|
|
7921
|
-
const httpCode = result.HttpStatus ?? result.HttpCode ?? null;
|
|
7922
|
-
let derivedInIndex = null;
|
|
7923
|
-
if (result.InIndex != null) {
|
|
7924
|
-
derivedInIndex = result.InIndex;
|
|
7925
|
-
} else if (result.DocumentSize != null && result.DocumentSize > 0) {
|
|
7926
|
-
derivedInIndex = true;
|
|
7927
|
-
}
|
|
7928
|
-
const lastCrawledDate = parseBingDate(result.LastCrawledDate);
|
|
7929
|
-
const inIndexDate = parseBingDate(result.InIndexDate);
|
|
7930
|
-
const discoveryDate = parseBingDate(result.DiscoveryDate);
|
|
7931
|
-
app.db.insert(bingUrlInspections).values({
|
|
7932
|
-
id,
|
|
7933
|
-
projectId: project.id,
|
|
7934
|
-
url,
|
|
7935
|
-
httpCode,
|
|
7936
|
-
inIndex: derivedInIndex === true ? 1 : derivedInIndex === false ? 0 : null,
|
|
7937
|
-
lastCrawledDate,
|
|
7938
|
-
inIndexDate,
|
|
7939
|
-
inspectedAt: now,
|
|
7940
|
-
createdAt: now,
|
|
7941
|
-
documentSize: result.DocumentSize ?? null,
|
|
7942
|
-
anchorCount: result.AnchorCount ?? null,
|
|
7943
|
-
discoveryDate
|
|
7944
|
-
}).run();
|
|
7945
|
-
return {
|
|
7946
|
-
id,
|
|
7947
|
-
url,
|
|
7948
|
-
httpCode,
|
|
7949
|
-
inIndex: derivedInIndex,
|
|
7950
|
-
lastCrawledDate,
|
|
7951
|
-
inIndexDate,
|
|
7952
|
-
inspectedAt: now,
|
|
7953
|
-
documentSize: result.DocumentSize ?? null,
|
|
7954
|
-
anchorCount: result.AnchorCount ?? null,
|
|
7955
|
-
discoveryDate
|
|
7956
|
-
};
|
|
7957
8003
|
});
|
|
7958
8004
|
app.post("/projects/:name/bing/request-indexing", async (request, reply) => {
|
|
7959
8005
|
const store = requireConnectionStore(reply);
|
|
@@ -8434,18 +8480,28 @@ async function ga4Routes(app, opts) {
|
|
|
8434
8480
|
const syncAi = !only || only === "ai";
|
|
8435
8481
|
const syncSocial = !only || only === "social";
|
|
8436
8482
|
const syncSummary = !only;
|
|
8437
|
-
const
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8483
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8484
|
+
const runId = crypto16.randomUUID();
|
|
8485
|
+
app.db.insert(runs).values({
|
|
8486
|
+
id: runId,
|
|
8487
|
+
projectId: project.id,
|
|
8488
|
+
kind: RunKinds["ga-sync"],
|
|
8489
|
+
status: RunStatuses.running,
|
|
8490
|
+
trigger: RunTriggers.manual,
|
|
8491
|
+
startedAt,
|
|
8492
|
+
createdAt: startedAt
|
|
8493
|
+
}).run();
|
|
8442
8494
|
try {
|
|
8495
|
+
const { accessToken, propertyId } = await resolveGa4AccessToken(opts, project.name, project.canonicalDomain);
|
|
8496
|
+
let rows = [];
|
|
8497
|
+
let aiReferrals = [];
|
|
8498
|
+
let socialReferrals = [];
|
|
8443
8499
|
const fetches = [fetchAggregateSummary(accessToken, propertyId, days)];
|
|
8444
8500
|
if (syncTraffic) fetches.push(fetchTrafficByLandingPage(accessToken, propertyId, days));
|
|
8445
8501
|
if (syncAi) fetches.push(fetchAiReferrals(accessToken, propertyId, days));
|
|
8446
8502
|
if (syncSocial) fetches.push(fetchSocialReferrals(accessToken, propertyId, days));
|
|
8447
8503
|
const results = await Promise.all(fetches);
|
|
8448
|
-
summary = results[0];
|
|
8504
|
+
const summary = results[0];
|
|
8449
8505
|
let idx = 1;
|
|
8450
8506
|
if (syncTraffic) {
|
|
8451
8507
|
rows = results[idx++];
|
|
@@ -8456,111 +8512,118 @@ async function ga4Routes(app, opts) {
|
|
|
8456
8512
|
if (syncSocial) {
|
|
8457
8513
|
socialReferrals = results[idx++];
|
|
8458
8514
|
}
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
users: row.users,
|
|
8483
|
-
syncedAt: now
|
|
8484
|
-
}).run();
|
|
8515
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8516
|
+
app.db.transaction((tx) => {
|
|
8517
|
+
if (syncTraffic) {
|
|
8518
|
+
tx.delete(gaTrafficSnapshots).where(
|
|
8519
|
+
and6(
|
|
8520
|
+
eq17(gaTrafficSnapshots.projectId, project.id),
|
|
8521
|
+
sql3`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
|
|
8522
|
+
sql3`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
|
|
8523
|
+
)
|
|
8524
|
+
).run();
|
|
8525
|
+
for (const row of rows) {
|
|
8526
|
+
tx.insert(gaTrafficSnapshots).values({
|
|
8527
|
+
id: crypto16.randomUUID(),
|
|
8528
|
+
projectId: project.id,
|
|
8529
|
+
date: row.date,
|
|
8530
|
+
landingPage: row.landingPage,
|
|
8531
|
+
sessions: row.sessions,
|
|
8532
|
+
organicSessions: row.organicSessions,
|
|
8533
|
+
users: row.users,
|
|
8534
|
+
syncedAt: now,
|
|
8535
|
+
syncRunId: runId
|
|
8536
|
+
}).run();
|
|
8537
|
+
}
|
|
8485
8538
|
}
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
)
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8539
|
+
if (syncAi) {
|
|
8540
|
+
tx.delete(gaAiReferrals).where(
|
|
8541
|
+
and6(
|
|
8542
|
+
eq17(gaAiReferrals.projectId, project.id),
|
|
8543
|
+
sql3`${gaAiReferrals.date} >= ${summary.periodStart}`,
|
|
8544
|
+
sql3`${gaAiReferrals.date} <= ${summary.periodEnd}`
|
|
8545
|
+
)
|
|
8546
|
+
).run();
|
|
8547
|
+
for (const row of aiReferrals) {
|
|
8548
|
+
tx.insert(gaAiReferrals).values({
|
|
8549
|
+
id: crypto16.randomUUID(),
|
|
8550
|
+
projectId: project.id,
|
|
8551
|
+
date: row.date,
|
|
8552
|
+
source: row.source,
|
|
8553
|
+
medium: row.medium,
|
|
8554
|
+
sourceDimension: row.sourceDimension,
|
|
8555
|
+
sessions: row.sessions,
|
|
8556
|
+
users: row.users,
|
|
8557
|
+
syncedAt: now,
|
|
8558
|
+
syncRunId: runId
|
|
8559
|
+
}).run();
|
|
8560
|
+
}
|
|
8507
8561
|
}
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
)
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8562
|
+
if (syncSocial) {
|
|
8563
|
+
tx.delete(gaSocialReferrals).where(
|
|
8564
|
+
and6(
|
|
8565
|
+
eq17(gaSocialReferrals.projectId, project.id),
|
|
8566
|
+
sql3`${gaSocialReferrals.date} >= ${summary.periodStart}`,
|
|
8567
|
+
sql3`${gaSocialReferrals.date} <= ${summary.periodEnd}`
|
|
8568
|
+
)
|
|
8569
|
+
).run();
|
|
8570
|
+
for (const row of socialReferrals) {
|
|
8571
|
+
tx.insert(gaSocialReferrals).values({
|
|
8572
|
+
id: crypto16.randomUUID(),
|
|
8573
|
+
projectId: project.id,
|
|
8574
|
+
date: row.date,
|
|
8575
|
+
source: row.source,
|
|
8576
|
+
medium: row.medium,
|
|
8577
|
+
channelGroup: row.channelGroup,
|
|
8578
|
+
sessions: row.sessions,
|
|
8579
|
+
users: row.users,
|
|
8580
|
+
syncedAt: now,
|
|
8581
|
+
syncRunId: runId
|
|
8582
|
+
}).run();
|
|
8583
|
+
}
|
|
8584
|
+
}
|
|
8585
|
+
if (syncSummary) {
|
|
8586
|
+
tx.delete(gaTrafficSummaries).where(eq17(gaTrafficSummaries.projectId, project.id)).run();
|
|
8587
|
+
tx.insert(gaTrafficSummaries).values({
|
|
8519
8588
|
id: crypto16.randomUUID(),
|
|
8520
8589
|
projectId: project.id,
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8590
|
+
periodStart: summary.periodStart,
|
|
8591
|
+
periodEnd: summary.periodEnd,
|
|
8592
|
+
totalSessions: summary.totalSessions,
|
|
8593
|
+
totalOrganicSessions: summary.totalOrganicSessions,
|
|
8594
|
+
totalUsers: summary.totalUsers,
|
|
8595
|
+
syncedAt: now,
|
|
8596
|
+
syncRunId: runId
|
|
8528
8597
|
}).run();
|
|
8529
8598
|
}
|
|
8530
|
-
}
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
aiReferralCount: aiReferrals.length,
|
|
8559
|
-
socialReferralCount: socialReferrals.length,
|
|
8560
|
-
days,
|
|
8561
|
-
syncedAt: now,
|
|
8562
|
-
...syncedComponents ? { syncedComponents } : {}
|
|
8563
|
-
};
|
|
8599
|
+
});
|
|
8600
|
+
app.db.update(runs).set({ status: RunStatuses.completed, finishedAt: now }).where(eq17(runs.id, runId)).run();
|
|
8601
|
+
const syncedComponents = only ? [only, ...only !== "social" && only !== "ai" && only !== "traffic" ? [] : []] : void 0;
|
|
8602
|
+
gaLog("info", "sync.complete", {
|
|
8603
|
+
projectId: project.id,
|
|
8604
|
+
runId,
|
|
8605
|
+
rowCount: rows.length,
|
|
8606
|
+
aiReferralCount: aiReferrals.length,
|
|
8607
|
+
socialReferralCount: socialReferrals.length,
|
|
8608
|
+
days,
|
|
8609
|
+
totalUsers: summary.totalUsers,
|
|
8610
|
+
...only ? { only } : {}
|
|
8611
|
+
});
|
|
8612
|
+
return {
|
|
8613
|
+
synced: true,
|
|
8614
|
+
rowCount: rows.length,
|
|
8615
|
+
aiReferralCount: aiReferrals.length,
|
|
8616
|
+
socialReferralCount: socialReferrals.length,
|
|
8617
|
+
days,
|
|
8618
|
+
syncedAt: now,
|
|
8619
|
+
...syncedComponents ? { syncedComponents } : {}
|
|
8620
|
+
};
|
|
8621
|
+
} catch (e) {
|
|
8622
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
8623
|
+
gaLog("error", "sync.fetch-failed", { projectId: project.id, runId, error: msg });
|
|
8624
|
+
app.db.update(runs).set({ status: RunStatuses.failed, error: msg, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq17(runs.id, runId)).run();
|
|
8625
|
+
throw e;
|
|
8626
|
+
}
|
|
8564
8627
|
});
|
|
8565
8628
|
app.get("/projects/:name/ga/traffic", async (request, _reply) => {
|
|
8566
8629
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -9049,7 +9112,8 @@ async function fetchJson(connection, siteUrl, path7, init) {
|
|
|
9049
9112
|
});
|
|
9050
9113
|
if (res.status === 401 || res.status === 403) {
|
|
9051
9114
|
const text = await res.text().catch(() => "");
|
|
9052
|
-
|
|
9115
|
+
const errorMessage = buildAuthErrorMessage(res, text);
|
|
9116
|
+
throw new WordpressApiError("AUTH_INVALID", errorMessage, res.status);
|
|
9053
9117
|
}
|
|
9054
9118
|
if (res.status === 404) {
|
|
9055
9119
|
throw new WordpressApiError("NOT_FOUND", "WordPress endpoint not found", 404);
|
|
@@ -12250,56 +12314,63 @@ var chatgptTarget = {
|
|
|
12250
12314
|
}
|
|
12251
12315
|
return text;
|
|
12252
12316
|
},
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12261
|
-
|
|
12317
|
+
extractCitations(client) {
|
|
12318
|
+
return (async () => {
|
|
12319
|
+
const { result } = await client.Runtime.evaluate({
|
|
12320
|
+
expression: `(() => {
|
|
12321
|
+
const sources = [];
|
|
12322
|
+
const seen = new Set();
|
|
12323
|
+
const turns = document.querySelectorAll('[data-message-author-role="assistant"]');
|
|
12324
|
+
const last = turns.length ? turns[turns.length - 1] : null;
|
|
12325
|
+
if (!last) return [];
|
|
12262
12326
|
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12327
|
+
const links = last.querySelectorAll('a[href]');
|
|
12328
|
+
for (const link of links) {
|
|
12329
|
+
const href = link.getAttribute('href');
|
|
12330
|
+
if (!href) continue;
|
|
12331
|
+
let hostname = '';
|
|
12332
|
+
try {
|
|
12333
|
+
const url = new URL(href);
|
|
12334
|
+
hostname = url.hostname.replace(/^www\\./, '');
|
|
12335
|
+
} catch {
|
|
12336
|
+
// Check for relative links or weird protocols
|
|
12337
|
+
if (href.startsWith('/') || href.startsWith('http')) {
|
|
12338
|
+
hostname = href;
|
|
12339
|
+
} else {
|
|
12340
|
+
continue;
|
|
12341
|
+
}
|
|
12342
|
+
}
|
|
12343
|
+
|
|
12344
|
+
if (!seen.has(href) && hostname !== 'chatgpt.com' && hostname !== 'openai.com') {
|
|
12345
|
+
seen.add(href);
|
|
12346
|
+
sources.push({
|
|
12347
|
+
uri: href,
|
|
12348
|
+
title: hostname || href,
|
|
12349
|
+
});
|
|
12350
|
+
}
|
|
12284
12351
|
}
|
|
12285
|
-
}
|
|
12286
12352
|
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12353
|
+
// Also check for citation superscripts that may reference sources
|
|
12354
|
+
const citeButtons = last.querySelectorAll('[data-testid="citation-button"], .citation-button');
|
|
12355
|
+
for (const btn of citeButtons) {
|
|
12356
|
+
const href = btn.getAttribute('data-href') || btn.closest('a')?.getAttribute('href');
|
|
12357
|
+
const title = btn.getAttribute('data-title') || btn.textContent?.trim();
|
|
12358
|
+
if (href && !seen.has(href)) {
|
|
12359
|
+
let hostname = '';
|
|
12360
|
+
try { hostname = new URL(href).hostname.replace(/^www\\./, ''); } catch {}
|
|
12361
|
+
if (hostname !== 'chatgpt.com' && hostname !== 'openai.com') {
|
|
12362
|
+
seen.add(href);
|
|
12363
|
+
sources.push({ uri: href, title: title || hostname || href });
|
|
12364
|
+
}
|
|
12365
|
+
}
|
|
12295
12366
|
}
|
|
12296
|
-
}
|
|
12297
12367
|
|
|
12298
|
-
|
|
12299
|
-
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12368
|
+
return sources;
|
|
12369
|
+
})()`,
|
|
12370
|
+
returnByValue: true
|
|
12371
|
+
});
|
|
12372
|
+
return result.value ?? [];
|
|
12373
|
+
})();
|
|
12303
12374
|
}
|
|
12304
12375
|
};
|
|
12305
12376
|
async function waitForElement(client, selector, timeoutMs) {
|
|
@@ -12460,10 +12531,11 @@ var cdpChatgptAdapter = {
|
|
|
12460
12531
|
const conn = getConnection(config);
|
|
12461
12532
|
const health = await conn.healthcheck();
|
|
12462
12533
|
if (!health.connected) {
|
|
12534
|
+
const port = config.cdpEndpoint?.split(":").pop() || "9222";
|
|
12463
12535
|
return {
|
|
12464
12536
|
ok: false,
|
|
12465
12537
|
provider: "cdp:chatgpt",
|
|
12466
|
-
message: `Chrome not reachable at ${config.cdpEndpoint}`
|
|
12538
|
+
message: `Chrome not reachable at ${config.cdpEndpoint}. Ensure Chrome is running with --remote-debugging-port=${port}`
|
|
12467
12539
|
};
|
|
12468
12540
|
}
|
|
12469
12541
|
return {
|
|
@@ -15085,6 +15157,70 @@ function serializeSessionCookie(opts) {
|
|
|
15085
15157
|
}
|
|
15086
15158
|
return parts.join("; ");
|
|
15087
15159
|
}
|
|
15160
|
+
function migrateDbCredentialsToConfig(db, config) {
|
|
15161
|
+
try {
|
|
15162
|
+
const googleColCheck = db.all(sql6.raw(
|
|
15163
|
+
`SELECT COUNT(*) as c FROM pragma_table_info('google_connections') WHERE name = 'access_token'`
|
|
15164
|
+
));
|
|
15165
|
+
if (googleColCheck[0]?.c) {
|
|
15166
|
+
const rows = db.all(sql6.raw(
|
|
15167
|
+
`SELECT domain, connection_type, property_id, sitemap_url, access_token, refresh_token, token_expires_at, scopes, created_at, updated_at FROM google_connections WHERE refresh_token IS NOT NULL AND refresh_token != ''`
|
|
15168
|
+
));
|
|
15169
|
+
let migrated = 0;
|
|
15170
|
+
for (const row of rows) {
|
|
15171
|
+
const connType = row.connection_type;
|
|
15172
|
+
const existing = getGoogleConnection(config, row.domain, connType);
|
|
15173
|
+
if (existing?.refreshToken) continue;
|
|
15174
|
+
upsertGoogleConnection(config, {
|
|
15175
|
+
domain: row.domain,
|
|
15176
|
+
connectionType: connType,
|
|
15177
|
+
propertyId: row.property_id ?? null,
|
|
15178
|
+
sitemapUrl: row.sitemap_url ?? null,
|
|
15179
|
+
accessToken: row.access_token ?? void 0,
|
|
15180
|
+
refreshToken: row.refresh_token ?? null,
|
|
15181
|
+
tokenExpiresAt: row.token_expires_at ?? null,
|
|
15182
|
+
scopes: parseJsonColumn(row.scopes, []),
|
|
15183
|
+
createdAt: row.created_at,
|
|
15184
|
+
updatedAt: row.updated_at
|
|
15185
|
+
});
|
|
15186
|
+
migrated++;
|
|
15187
|
+
}
|
|
15188
|
+
if (migrated > 0) {
|
|
15189
|
+
saveConfigPatch({ google: config.google });
|
|
15190
|
+
log8.info("credentials.migrated", { type: "google", count: migrated });
|
|
15191
|
+
}
|
|
15192
|
+
}
|
|
15193
|
+
const gaColCheck = db.all(sql6.raw(
|
|
15194
|
+
`SELECT COUNT(*) as c FROM pragma_table_info('ga_connections') WHERE name = 'private_key'`
|
|
15195
|
+
));
|
|
15196
|
+
if (gaColCheck[0]?.c) {
|
|
15197
|
+
const rows = db.all(sql6.raw(
|
|
15198
|
+
`SELECT id, project_id, property_id, client_email, private_key, created_at, updated_at FROM ga_connections WHERE private_key IS NOT NULL AND private_key != ''`
|
|
15199
|
+
));
|
|
15200
|
+
let migrated = 0;
|
|
15201
|
+
for (const row of rows) {
|
|
15202
|
+
const project = db.select({ name: projects.name }).from(projects).where(eq23(projects.id, row.project_id)).get();
|
|
15203
|
+
if (!project) continue;
|
|
15204
|
+
const existing = getGa4Connection(config, project.name);
|
|
15205
|
+
if (existing?.privateKey) continue;
|
|
15206
|
+
upsertGa4Connection(config, {
|
|
15207
|
+
projectName: project.name,
|
|
15208
|
+
propertyId: row.property_id,
|
|
15209
|
+
clientEmail: row.client_email,
|
|
15210
|
+
privateKey: row.private_key,
|
|
15211
|
+
createdAt: row.created_at,
|
|
15212
|
+
updatedAt: row.updated_at
|
|
15213
|
+
});
|
|
15214
|
+
migrated++;
|
|
15215
|
+
}
|
|
15216
|
+
if (migrated > 0) {
|
|
15217
|
+
saveConfigPatch({ ga4: config.ga4 });
|
|
15218
|
+
log8.info("credentials.migrated", { type: "ga4", count: migrated });
|
|
15219
|
+
}
|
|
15220
|
+
}
|
|
15221
|
+
} catch {
|
|
15222
|
+
}
|
|
15223
|
+
}
|
|
15088
15224
|
async function createServer(opts) {
|
|
15089
15225
|
const logger = opts.logger === false ? false : process.stdout.isTTY ? {
|
|
15090
15226
|
transport: {
|
|
@@ -15109,6 +15245,7 @@ async function createServer(opts) {
|
|
|
15109
15245
|
quota: opts.config.geminiQuota
|
|
15110
15246
|
};
|
|
15111
15247
|
}
|
|
15248
|
+
migrateDbCredentialsToConfig(opts.db, opts.config);
|
|
15112
15249
|
log8.info("providers.configured", { providers: Object.keys(providers).filter((k) => {
|
|
15113
15250
|
const p = providers[k];
|
|
15114
15251
|
return p?.apiKey || p?.baseUrl || p?.vertexProject;
|