@ainyc/canonry 4.51.0 → 4.51.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/{BacklinksPage-DIZCcqsP.js → BacklinksPage-BtURdL_I.js} +1 -1
- package/assets/assets/ProjectPage-_etyTtZ9.js +6 -0
- package/assets/assets/{RunRow-DqezNIUy.js → RunRow-NfzAq5p2.js} +1 -1
- package/assets/assets/{RunsPage-CfvTJ9Ny.js → RunsPage-CPPFYq6U.js} +1 -1
- package/assets/assets/{SettingsPage-HfMGIa5v.js → SettingsPage-CuB6YrAV.js} +1 -1
- package/assets/assets/{TrafficPage-DV_Dvpl3.js → TrafficPage-Dn0XTJoC.js} +1 -1
- package/assets/assets/TrafficSourceDetailPage-CTG7aAlv.js +1 -0
- package/assets/assets/{arrow-left-DpxpMUNt.js → arrow-left-VZ7oOCHS.js} +1 -1
- package/assets/assets/{index-DKBPD33e.js → index-VMFHNbas.js} +109 -109
- package/assets/assets/server-traffic-Bym-drXr.js +1 -0
- package/assets/assets/{trash-2-CnBiLbiZ.js → trash-2-BNsIoa7t.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-2ARCCG5E.js → chunk-FYGBW3SM.js} +4 -0
- package/dist/{chunk-GGXU5VKI.js → chunk-HMZKIOLG.js} +1 -1
- package/dist/{chunk-DLDLDWH4.js → chunk-QZ5XSM6C.js} +34 -1
- package/dist/{chunk-FDR3G6SB.js → chunk-WBO5S3IX.js} +3193 -258
- package/dist/cli.js +40 -8
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-XMZEWLCW.js → intelligence-service-2XL2M7QP.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +9 -9
- package/assets/assets/ProjectPage-R2cxJb5Y.js +0 -6
- package/assets/assets/TrafficSourceDetailPage-lefreKBO.js +0 -1
- package/assets/assets/server-traffic-Bm8iKtXK.js +0 -1
|
@@ -2,10 +2,11 @@ import {
|
|
|
2
2
|
ApiClient,
|
|
3
3
|
canonryMcpTools,
|
|
4
4
|
configExists,
|
|
5
|
+
getConfigPath,
|
|
5
6
|
loadConfig,
|
|
6
7
|
loadConfigRaw,
|
|
7
8
|
saveConfigPatch
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-HMZKIOLG.js";
|
|
9
10
|
import {
|
|
10
11
|
DEFAULT_RUN_HISTORY_LIMIT,
|
|
11
12
|
IntelligenceService,
|
|
@@ -82,7 +83,7 @@ import {
|
|
|
82
83
|
smoothedRunDelta,
|
|
83
84
|
trafficSources,
|
|
84
85
|
usageCounters
|
|
85
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-QZ5XSM6C.js";
|
|
86
87
|
import {
|
|
87
88
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
88
89
|
AGENT_PROVIDER_IDS,
|
|
@@ -247,6 +248,7 @@ import {
|
|
|
247
248
|
runInProgress,
|
|
248
249
|
runNotCancellable,
|
|
249
250
|
runTriggerRequestSchema,
|
|
251
|
+
runtimeStateMissing,
|
|
250
252
|
schedulableRunKindSchema,
|
|
251
253
|
scheduleDtoSchema,
|
|
252
254
|
scheduleUpsertRequestSchema,
|
|
@@ -282,7 +284,7 @@ import {
|
|
|
282
284
|
wordpressSchemaDeployResultDtoSchema,
|
|
283
285
|
wordpressSchemaStatusResultDtoSchema,
|
|
284
286
|
wordpressStatusDtoSchema
|
|
285
|
-
} from "./chunk-
|
|
287
|
+
} from "./chunk-FYGBW3SM.js";
|
|
286
288
|
|
|
287
289
|
// src/telemetry.ts
|
|
288
290
|
import crypto from "crypto";
|
|
@@ -571,12 +573,15 @@ function checkLatestVersionForServer(opts) {
|
|
|
571
573
|
// src/server.ts
|
|
572
574
|
import { createRequire as createRequire4 } from "module";
|
|
573
575
|
import crypto35 from "crypto";
|
|
574
|
-
import
|
|
576
|
+
import fs15 from "fs";
|
|
575
577
|
import path15 from "path";
|
|
576
578
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
577
579
|
import { eq as eq42 } from "drizzle-orm";
|
|
578
580
|
import Fastify from "fastify";
|
|
579
581
|
|
|
582
|
+
// ../api-routes/src/index.ts
|
|
583
|
+
import fs8 from "fs";
|
|
584
|
+
|
|
580
585
|
// ../api-routes/src/auth.ts
|
|
581
586
|
import crypto2 from "crypto";
|
|
582
587
|
import { eq } from "drizzle-orm";
|
|
@@ -669,9 +674,22 @@ function writeAuditLog(db, entry) {
|
|
|
669
674
|
entityType: entry.entityType,
|
|
670
675
|
entityId: entry.entityId ?? null,
|
|
671
676
|
diff: entry.diff != null ? JSON.stringify(entry.diff) : null,
|
|
677
|
+
userAgent: entry.userAgent ?? null,
|
|
678
|
+
actorSession: entry.actorSession ?? null,
|
|
672
679
|
createdAt: now
|
|
673
680
|
}).run();
|
|
674
681
|
}
|
|
682
|
+
function auditFromRequest(request, entry) {
|
|
683
|
+
const ua = request.headers["user-agent"];
|
|
684
|
+
const userAgent = Array.isArray(ua) ? ua.join(", ") : ua ?? null;
|
|
685
|
+
const sess = request.headers["x-canonry-actor-session"];
|
|
686
|
+
const actorSession = Array.isArray(sess) ? sess.join(", ") : sess ?? null;
|
|
687
|
+
return {
|
|
688
|
+
...entry,
|
|
689
|
+
userAgent: entry.userAgent ?? userAgent,
|
|
690
|
+
actorSession: entry.actorSession ?? actorSession
|
|
691
|
+
};
|
|
692
|
+
}
|
|
675
693
|
function resolveSnapshotMentionResult(snapshot, project) {
|
|
676
694
|
if (snapshot.answerText) {
|
|
677
695
|
const domains = effectiveDomains({
|
|
@@ -1023,6 +1041,12 @@ function aliasArraysEqual(a, b) {
|
|
|
1023
1041
|
// ../api-routes/src/queries.ts
|
|
1024
1042
|
import crypto5 from "crypto";
|
|
1025
1043
|
import { eq as eq4, inArray, sql as sql3 } from "drizzle-orm";
|
|
1044
|
+
function preserveSnapshotQueryText(tx, projectId, queryIds) {
|
|
1045
|
+
const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(inArray(queries.id, queryIds)).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq4(queries.projectId, projectId)).all();
|
|
1046
|
+
for (const q of candidates) {
|
|
1047
|
+
tx.update(querySnapshots).set({ queryText: q.text }).where(eq4(querySnapshots.queryId, q.id)).run();
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1026
1050
|
async function queryRoutes(app, opts) {
|
|
1027
1051
|
app.get("/projects/:name/queries", async (request, reply) => {
|
|
1028
1052
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -1037,6 +1061,7 @@ async function queryRoutes(app, opts) {
|
|
|
1037
1061
|
}
|
|
1038
1062
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1039
1063
|
app.db.transaction((tx) => {
|
|
1064
|
+
preserveSnapshotQueryText(tx, project.id);
|
|
1040
1065
|
tx.delete(queries).where(eq4(queries.projectId, project.id)).run();
|
|
1041
1066
|
for (const q of body.queries) {
|
|
1042
1067
|
tx.insert(queries).values({
|
|
@@ -1047,13 +1072,13 @@ async function queryRoutes(app, opts) {
|
|
|
1047
1072
|
createdAt: now
|
|
1048
1073
|
}).run();
|
|
1049
1074
|
}
|
|
1050
|
-
writeAuditLog(tx, {
|
|
1075
|
+
writeAuditLog(tx, auditFromRequest(request, {
|
|
1051
1076
|
projectId: project.id,
|
|
1052
1077
|
actor: "api",
|
|
1053
1078
|
action: "queries.replaced",
|
|
1054
1079
|
entityType: "query",
|
|
1055
1080
|
diff: { queries: body.queries }
|
|
1056
|
-
});
|
|
1081
|
+
}));
|
|
1057
1082
|
});
|
|
1058
1083
|
const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
|
|
1059
1084
|
return reply.send(rows.map((r) => ({ id: r.id, query: r.query, createdAt: r.createdAt })));
|
|
@@ -1099,16 +1124,17 @@ async function queryRoutes(app, opts) {
|
|
|
1099
1124
|
const idsToDelete = existing.filter((q) => toDelete.has(q.query)).map((q) => q.id);
|
|
1100
1125
|
if (idsToDelete.length > 0) {
|
|
1101
1126
|
app.db.transaction((tx) => {
|
|
1127
|
+
preserveSnapshotQueryText(tx, project.id, idsToDelete);
|
|
1102
1128
|
for (const id of idsToDelete) {
|
|
1103
1129
|
tx.delete(queries).where(eq4(queries.id, id)).run();
|
|
1104
1130
|
}
|
|
1105
|
-
writeAuditLog(tx, {
|
|
1131
|
+
writeAuditLog(tx, auditFromRequest(request, {
|
|
1106
1132
|
projectId: project.id,
|
|
1107
1133
|
actor: "api",
|
|
1108
1134
|
action: "queries.deleted",
|
|
1109
1135
|
entityType: "query",
|
|
1110
1136
|
diff: { deleted: body.queries.filter((q) => existing.some((e) => e.query === q)) }
|
|
1111
|
-
});
|
|
1137
|
+
}));
|
|
1112
1138
|
});
|
|
1113
1139
|
}
|
|
1114
1140
|
const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
|
|
@@ -1138,13 +1164,13 @@ async function queryRoutes(app, opts) {
|
|
|
1138
1164
|
}
|
|
1139
1165
|
}
|
|
1140
1166
|
if (added.length > 0) {
|
|
1141
|
-
writeAuditLog(app.db, {
|
|
1167
|
+
writeAuditLog(app.db, auditFromRequest(request, {
|
|
1142
1168
|
projectId: project.id,
|
|
1143
1169
|
actor: "api",
|
|
1144
1170
|
action: "queries.appended",
|
|
1145
1171
|
entityType: "query",
|
|
1146
1172
|
diff: { added }
|
|
1147
|
-
});
|
|
1173
|
+
}));
|
|
1148
1174
|
}
|
|
1149
1175
|
const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
|
|
1150
1176
|
return reply.send(rows.map((r) => ({ id: r.id, query: r.query, createdAt: r.createdAt })));
|
|
@@ -1202,6 +1228,7 @@ async function queryRoutes(app, opts) {
|
|
|
1202
1228
|
}
|
|
1203
1229
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1204
1230
|
app.db.transaction((tx) => {
|
|
1231
|
+
preserveSnapshotQueryText(tx, project.id);
|
|
1205
1232
|
tx.delete(queries).where(eq4(queries.projectId, project.id)).run();
|
|
1206
1233
|
for (const keyword of body.keywords) {
|
|
1207
1234
|
tx.insert(queries).values({
|
|
@@ -1212,13 +1239,13 @@ async function queryRoutes(app, opts) {
|
|
|
1212
1239
|
createdAt: now
|
|
1213
1240
|
}).run();
|
|
1214
1241
|
}
|
|
1215
|
-
writeAuditLog(tx, {
|
|
1242
|
+
writeAuditLog(tx, auditFromRequest(request, {
|
|
1216
1243
|
projectId: project.id,
|
|
1217
1244
|
actor: "api",
|
|
1218
1245
|
action: "queries.replaced",
|
|
1219
1246
|
entityType: "query",
|
|
1220
1247
|
diff: { queries: body.keywords }
|
|
1221
|
-
});
|
|
1248
|
+
}));
|
|
1222
1249
|
});
|
|
1223
1250
|
const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
|
|
1224
1251
|
return reply.send(rows.map((r) => ({ id: r.id, keyword: r.query, createdAt: r.createdAt })));
|
|
@@ -1234,16 +1261,17 @@ async function queryRoutes(app, opts) {
|
|
|
1234
1261
|
const idsToDelete = existing.filter((q) => toDelete.has(q.query)).map((q) => q.id);
|
|
1235
1262
|
if (idsToDelete.length > 0) {
|
|
1236
1263
|
app.db.transaction((tx) => {
|
|
1264
|
+
preserveSnapshotQueryText(tx, project.id, idsToDelete);
|
|
1237
1265
|
for (const id of idsToDelete) {
|
|
1238
1266
|
tx.delete(queries).where(eq4(queries.id, id)).run();
|
|
1239
1267
|
}
|
|
1240
|
-
writeAuditLog(tx, {
|
|
1268
|
+
writeAuditLog(tx, auditFromRequest(request, {
|
|
1241
1269
|
projectId: project.id,
|
|
1242
1270
|
actor: "api",
|
|
1243
1271
|
action: "queries.deleted",
|
|
1244
1272
|
entityType: "query",
|
|
1245
1273
|
diff: { deleted: body.keywords.filter((keyword) => existing.some((e) => e.query === keyword)) }
|
|
1246
|
-
});
|
|
1274
|
+
}));
|
|
1247
1275
|
});
|
|
1248
1276
|
}
|
|
1249
1277
|
const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
|
|
@@ -1273,13 +1301,13 @@ async function queryRoutes(app, opts) {
|
|
|
1273
1301
|
}
|
|
1274
1302
|
}
|
|
1275
1303
|
if (added.length > 0) {
|
|
1276
|
-
writeAuditLog(app.db, {
|
|
1304
|
+
writeAuditLog(app.db, auditFromRequest(request, {
|
|
1277
1305
|
projectId: project.id,
|
|
1278
1306
|
actor: "api",
|
|
1279
1307
|
action: "queries.appended",
|
|
1280
1308
|
entityType: "query",
|
|
1281
1309
|
diff: { added }
|
|
1282
|
-
});
|
|
1310
|
+
}));
|
|
1283
1311
|
}
|
|
1284
1312
|
const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
|
|
1285
1313
|
return reply.send(rows.map((r) => ({ id: r.id, keyword: r.query, createdAt: r.createdAt })));
|
|
@@ -1639,8 +1667,10 @@ async function runRoutes(app, opts) {
|
|
|
1639
1667
|
const limit = parseListLimit(request.query.limit, 500, 5e3);
|
|
1640
1668
|
const since = parseListSince(request.query.since);
|
|
1641
1669
|
const includeProbe = request.query.includeProbe === "1" || request.query.includeProbe === "true";
|
|
1670
|
+
const kind = parseListKind(request.query.kind);
|
|
1642
1671
|
const filters = [gte(runs.createdAt, since)];
|
|
1643
1672
|
if (!includeProbe) filters.push(notProbeRun());
|
|
1673
|
+
if (kind) filters.push(eq7(runs.kind, kind));
|
|
1644
1674
|
const rows = app.db.select().from(runs).where(and2(...filters)).orderBy(desc(runs.createdAt), desc(runs.id)).limit(limit).all();
|
|
1645
1675
|
return reply.send(rows.map(formatRun));
|
|
1646
1676
|
});
|
|
@@ -1749,6 +1779,14 @@ function parseListLimit(raw, defaultValue, max) {
|
|
|
1749
1779
|
}
|
|
1750
1780
|
return Math.min(parsed, max);
|
|
1751
1781
|
}
|
|
1782
|
+
function parseListKind(raw) {
|
|
1783
|
+
if (raw === void 0 || raw === "") return null;
|
|
1784
|
+
const validKinds = Object.values(RunKinds);
|
|
1785
|
+
if (!validKinds.includes(raw)) {
|
|
1786
|
+
throw validationError(`"kind" must be one of: ${validKinds.join(", ")}`);
|
|
1787
|
+
}
|
|
1788
|
+
return raw;
|
|
1789
|
+
}
|
|
1752
1790
|
function parseListSince(raw) {
|
|
1753
1791
|
if (raw === void 0) {
|
|
1754
1792
|
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
|
|
@@ -2495,9 +2533,24 @@ async function historyRoutes(app) {
|
|
|
2495
2533
|
...snapshot,
|
|
2496
2534
|
answerMentioned: resolveSnapshotAnswerMentioned(snapshot, project)
|
|
2497
2535
|
}));
|
|
2536
|
+
const queryByText = /* @__PURE__ */ new Map();
|
|
2537
|
+
for (const q of projectQueries) queryByText.set(q.query, q);
|
|
2538
|
+
function resolveSnapQueryId(snap) {
|
|
2539
|
+
if (snap.queryId) return snap.queryId;
|
|
2540
|
+
if (snap.queryText) {
|
|
2541
|
+
const match = queryByText.get(snap.queryText);
|
|
2542
|
+
if (match) return match.id;
|
|
2543
|
+
}
|
|
2544
|
+
return null;
|
|
2545
|
+
}
|
|
2546
|
+
const allSnapshotsResolved = allSnapshots.map((s) => ({
|
|
2547
|
+
...s,
|
|
2548
|
+
resolvedQueryId: resolveSnapQueryId(s)
|
|
2549
|
+
}));
|
|
2498
2550
|
const deduped = /* @__PURE__ */ new Map();
|
|
2499
|
-
for (const snap of
|
|
2500
|
-
|
|
2551
|
+
for (const snap of allSnapshotsResolved) {
|
|
2552
|
+
if (!snap.resolvedQueryId) continue;
|
|
2553
|
+
const key = `${snap.runId}:${snap.resolvedQueryId}`;
|
|
2501
2554
|
const existing = deduped.get(key);
|
|
2502
2555
|
if (!existing || !existing.answerMentioned && snap.answerMentioned || existing.answerMentioned === snap.answerMentioned && snap.citationState === CitationStates.cited) {
|
|
2503
2556
|
deduped.set(key, snap);
|
|
@@ -2505,15 +2558,17 @@ async function historyRoutes(app) {
|
|
|
2505
2558
|
}
|
|
2506
2559
|
const dedupedSnapshots = [...deduped.values()];
|
|
2507
2560
|
const rawByQueryProvider = /* @__PURE__ */ new Map();
|
|
2508
|
-
for (const snap of
|
|
2509
|
-
|
|
2561
|
+
for (const snap of allSnapshotsResolved) {
|
|
2562
|
+
if (!snap.resolvedQueryId) continue;
|
|
2563
|
+
const key = `${snap.resolvedQueryId}::${snap.provider}`;
|
|
2510
2564
|
const arr = rawByQueryProvider.get(key);
|
|
2511
2565
|
if (arr) arr.push(snap);
|
|
2512
2566
|
else rawByQueryProvider.set(key, [snap]);
|
|
2513
2567
|
}
|
|
2514
2568
|
const rawByQueryModel = /* @__PURE__ */ new Map();
|
|
2515
|
-
for (const snap of
|
|
2516
|
-
|
|
2569
|
+
for (const snap of allSnapshotsResolved) {
|
|
2570
|
+
if (!snap.resolvedQueryId) continue;
|
|
2571
|
+
const key = `${snap.resolvedQueryId}::${snap.provider}:${snap.model ?? "unknown"}`;
|
|
2517
2572
|
const arr = rawByQueryModel.get(key);
|
|
2518
2573
|
if (arr) arr.push(snap);
|
|
2519
2574
|
else rawByQueryModel.set(key, [snap]);
|
|
@@ -2560,7 +2615,7 @@ async function historyRoutes(app) {
|
|
|
2560
2615
|
});
|
|
2561
2616
|
}
|
|
2562
2617
|
const timeline = projectQueries.map((q) => {
|
|
2563
|
-
const qSnapshots = dedupedSnapshots.filter((s) => s.
|
|
2618
|
+
const qSnapshots = dedupedSnapshots.filter((s) => s.resolvedQueryId === q.id).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
2564
2619
|
const runEntries = computeTransitions(qSnapshots);
|
|
2565
2620
|
const providerRuns = {};
|
|
2566
2621
|
const providerKeys = [...rawByQueryProvider.keys()].filter((k) => k.startsWith(`${q.id}::`));
|
|
@@ -8387,6 +8442,39 @@ var scheduleKindQueryParameter = {
|
|
|
8387
8442
|
description: 'Schedulable run kind. Defaults to "answer-visibility" for backward compatibility.',
|
|
8388
8443
|
schema: { type: "string", enum: ["answer-visibility", "traffic-sync"] }
|
|
8389
8444
|
};
|
|
8445
|
+
var runsListKindQueryParameter = {
|
|
8446
|
+
name: "kind",
|
|
8447
|
+
in: "query",
|
|
8448
|
+
description: "Restrict results to a single run kind. Without this filter, integration syncs (bing-inspect, gsc-sync, ga-sync) can fill the default 500-row cap within minutes on busy projects and push answer-visibility runs out of the response.",
|
|
8449
|
+
schema: {
|
|
8450
|
+
type: "string",
|
|
8451
|
+
enum: [
|
|
8452
|
+
"answer-visibility",
|
|
8453
|
+
"site-audit",
|
|
8454
|
+
"gsc-sync",
|
|
8455
|
+
"inspect-sitemap",
|
|
8456
|
+
"ga-sync",
|
|
8457
|
+
"bing-inspect",
|
|
8458
|
+
"bing-inspect-sitemap",
|
|
8459
|
+
"backlink-extract",
|
|
8460
|
+
"traffic-sync",
|
|
8461
|
+
"aeo-discover-seed",
|
|
8462
|
+
"aeo-discover-probe"
|
|
8463
|
+
]
|
|
8464
|
+
}
|
|
8465
|
+
};
|
|
8466
|
+
var runsListSinceQueryParameter = {
|
|
8467
|
+
name: "since",
|
|
8468
|
+
in: "query",
|
|
8469
|
+
description: "Only return runs with created_at >= this ISO 8601 timestamp. Defaults to 30 days ago.",
|
|
8470
|
+
schema: stringSchema
|
|
8471
|
+
};
|
|
8472
|
+
var runsListIncludeProbeQueryParameter = {
|
|
8473
|
+
name: "includeProbe",
|
|
8474
|
+
in: "query",
|
|
8475
|
+
description: 'Set to "1" or "true" to include probe runs. Probes are excluded by default because they are operator/agent test runs and must not pollute dashboard aggregates.',
|
|
8476
|
+
schema: stringSchema
|
|
8477
|
+
};
|
|
8390
8478
|
var reportAudienceQueryParameter = {
|
|
8391
8479
|
name: "audience",
|
|
8392
8480
|
in: "query",
|
|
@@ -8970,6 +9058,12 @@ var routeCatalog = [
|
|
|
8970
9058
|
path: "/api/v1/runs",
|
|
8971
9059
|
summary: "List all runs",
|
|
8972
9060
|
tags: ["runs"],
|
|
9061
|
+
parameters: [
|
|
9062
|
+
limitQueryParameter,
|
|
9063
|
+
runsListSinceQueryParameter,
|
|
9064
|
+
runsListIncludeProbeQueryParameter,
|
|
9065
|
+
runsListKindQueryParameter
|
|
9066
|
+
],
|
|
8973
9067
|
responses: {
|
|
8974
9068
|
200: jsonArrayResponse("Runs returned.", "RunDto")
|
|
8975
9069
|
}
|
|
@@ -12540,6 +12634,9 @@ var GA4_DEFAULT_SYNC_DAYS = 30;
|
|
|
12540
12634
|
var GA4_MAX_SYNC_DAYS = 90;
|
|
12541
12635
|
var GA4_REQUEST_TIMEOUT_MS = 3e4;
|
|
12542
12636
|
var GA4_MAX_PAGES = 50;
|
|
12637
|
+
var GA4_MAX_CONCURRENT_REQUESTS = 4;
|
|
12638
|
+
var GA4_MAX_RETRIES = 3;
|
|
12639
|
+
var GA4_INITIAL_RETRY_DELAY_MS = 1e3;
|
|
12543
12640
|
var GA4_DIMENSIONS = {
|
|
12544
12641
|
date: "date",
|
|
12545
12642
|
landingPagePlusQueryString: "landingPagePlusQueryString",
|
|
@@ -12560,10 +12657,14 @@ var GA4_METRICS = {
|
|
|
12560
12657
|
// ../integration-google-analytics/src/types.ts
|
|
12561
12658
|
var GA4ApiError = class extends Error {
|
|
12562
12659
|
status;
|
|
12563
|
-
|
|
12660
|
+
/** Seconds the GA4 API asked us to wait before retrying. Populated from the
|
|
12661
|
+
* `Retry-After` response header on 429 and 5xx responses when present. */
|
|
12662
|
+
retryAfterSeconds;
|
|
12663
|
+
constructor(message, status, retryAfterSeconds) {
|
|
12564
12664
|
super(message);
|
|
12565
12665
|
this.name = "GA4ApiError";
|
|
12566
12666
|
this.status = status;
|
|
12667
|
+
if (retryAfterSeconds !== void 0) this.retryAfterSeconds = retryAfterSeconds;
|
|
12567
12668
|
}
|
|
12568
12669
|
};
|
|
12569
12670
|
|
|
@@ -12659,81 +12760,155 @@ async function getAccessToken(clientEmail, privateKey) {
|
|
|
12659
12760
|
function escapeRegExp2(str) {
|
|
12660
12761
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12661
12762
|
}
|
|
12763
|
+
var gaInFlight = 0;
|
|
12764
|
+
var gaWaitQueue = [];
|
|
12765
|
+
async function acquireGa4Slot() {
|
|
12766
|
+
if (gaInFlight < GA4_MAX_CONCURRENT_REQUESTS) {
|
|
12767
|
+
gaInFlight++;
|
|
12768
|
+
return;
|
|
12769
|
+
}
|
|
12770
|
+
await new Promise((resolve) => gaWaitQueue.push(resolve));
|
|
12771
|
+
}
|
|
12772
|
+
function releaseGa4Slot() {
|
|
12773
|
+
const next = gaWaitQueue.shift();
|
|
12774
|
+
if (next) {
|
|
12775
|
+
next();
|
|
12776
|
+
} else {
|
|
12777
|
+
gaInFlight--;
|
|
12778
|
+
}
|
|
12779
|
+
}
|
|
12780
|
+
async function withGa4Limit(fn) {
|
|
12781
|
+
await acquireGa4Slot();
|
|
12782
|
+
try {
|
|
12783
|
+
return await fn();
|
|
12784
|
+
} finally {
|
|
12785
|
+
releaseGa4Slot();
|
|
12786
|
+
}
|
|
12787
|
+
}
|
|
12788
|
+
function parseRetryAfter(headerValue) {
|
|
12789
|
+
if (!headerValue) return void 0;
|
|
12790
|
+
const trimmed = headerValue.trim();
|
|
12791
|
+
const asNum = Number(trimmed);
|
|
12792
|
+
if (Number.isFinite(asNum) && asNum >= 0) return asNum;
|
|
12793
|
+
const asDate = Date.parse(trimmed);
|
|
12794
|
+
if (!Number.isNaN(asDate)) {
|
|
12795
|
+
const seconds = Math.max(0, (asDate - Date.now()) / 1e3);
|
|
12796
|
+
return seconds;
|
|
12797
|
+
}
|
|
12798
|
+
return void 0;
|
|
12799
|
+
}
|
|
12800
|
+
function isRetryableGa4Error(err) {
|
|
12801
|
+
if (err instanceof GA4ApiError) {
|
|
12802
|
+
return err.status === 429 || err.status >= 500;
|
|
12803
|
+
}
|
|
12804
|
+
return false;
|
|
12805
|
+
}
|
|
12806
|
+
async function withGa4Retry(fn, errLabel) {
|
|
12807
|
+
let lastError;
|
|
12808
|
+
for (let attempt = 0; attempt <= GA4_MAX_RETRIES; attempt++) {
|
|
12809
|
+
try {
|
|
12810
|
+
return await fn();
|
|
12811
|
+
} catch (err) {
|
|
12812
|
+
lastError = err;
|
|
12813
|
+
if (attempt >= GA4_MAX_RETRIES || !isRetryableGa4Error(err)) throw err;
|
|
12814
|
+
const ga4Err = err;
|
|
12815
|
+
const computedDelayMs = GA4_INITIAL_RETRY_DELAY_MS * Math.pow(2, attempt);
|
|
12816
|
+
const delayMs = ga4Err.retryAfterSeconds !== void 0 ? Math.max(0, ga4Err.retryAfterSeconds * 1e3) : computedDelayMs;
|
|
12817
|
+
ga4Log("info", `${errLabel}.retry`, {
|
|
12818
|
+
attempt: attempt + 1,
|
|
12819
|
+
maxAttempts: GA4_MAX_RETRIES + 1,
|
|
12820
|
+
status: ga4Err.status,
|
|
12821
|
+
delayMs,
|
|
12822
|
+
usedRetryAfter: ga4Err.retryAfterSeconds !== void 0
|
|
12823
|
+
});
|
|
12824
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
12825
|
+
}
|
|
12826
|
+
}
|
|
12827
|
+
throw lastError;
|
|
12828
|
+
}
|
|
12662
12829
|
async function runReport(accessToken, propertyId, request) {
|
|
12663
12830
|
validatePropertyId(propertyId);
|
|
12664
12831
|
const safePropertyId = encodeURIComponent(propertyId);
|
|
12665
12832
|
const url = `${GA4_DATA_API_BASE}/properties/${safePropertyId}:runReport`;
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12833
|
+
return withGa4Limit(() => withGa4Retry(async () => {
|
|
12834
|
+
const res = await fetch(url, {
|
|
12835
|
+
method: "POST",
|
|
12836
|
+
headers: {
|
|
12837
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
12838
|
+
"Content-Type": "application/json"
|
|
12839
|
+
},
|
|
12840
|
+
body: JSON.stringify(request),
|
|
12841
|
+
signal: AbortSignal.timeout(GA4_REQUEST_TIMEOUT_MS)
|
|
12842
|
+
});
|
|
12843
|
+
if (res.status === 401 || res.status === 403) {
|
|
12844
|
+
const body = await res.text().catch(() => "");
|
|
12845
|
+
let detail = "";
|
|
12846
|
+
try {
|
|
12847
|
+
const parsed = JSON.parse(body);
|
|
12848
|
+
if (parsed.error?.status === "SERVICE_DISABLED") {
|
|
12849
|
+
detail = " The Google Analytics Data API is not enabled for this GCP project. Enable it at: https://console.developers.google.com/apis/api/analyticsdata.googleapis.com/overview";
|
|
12850
|
+
} else if (parsed.error?.message) {
|
|
12851
|
+
detail = ` ${parsed.error.message}`;
|
|
12852
|
+
}
|
|
12853
|
+
} catch {
|
|
12854
|
+
if (body.length < 200) detail = ` ${body}`;
|
|
12684
12855
|
}
|
|
12685
|
-
|
|
12686
|
-
|
|
12856
|
+
ga4Log("error", "report.auth-failed", { propertyId, httpStatus: res.status });
|
|
12857
|
+
throw new GA4ApiError(
|
|
12858
|
+
`GA4 API authentication failed \u2014 check service account permissions.${detail}`,
|
|
12859
|
+
res.status
|
|
12860
|
+
);
|
|
12687
12861
|
}
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
throw new GA4ApiError(`GA4 API error (${res.status}): ${detail}`, res.status);
|
|
12703
|
-
}
|
|
12704
|
-
return await res.json();
|
|
12862
|
+
if (res.status === 429) {
|
|
12863
|
+
const retryAfterSeconds = parseRetryAfter(res.headers.get("retry-after"));
|
|
12864
|
+
ga4Log("error", "report.rate-limited", { propertyId, retryAfterSeconds });
|
|
12865
|
+
throw new GA4ApiError("GA4 API rate limit exceeded", 429, retryAfterSeconds);
|
|
12866
|
+
}
|
|
12867
|
+
if (!res.ok) {
|
|
12868
|
+
const body = await res.text();
|
|
12869
|
+
const retryAfterSeconds = res.status >= 500 ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
|
|
12870
|
+
ga4Log("error", "report.error", { propertyId, httpStatus: res.status, retryAfterSeconds });
|
|
12871
|
+
const detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
|
|
12872
|
+
throw new GA4ApiError(`GA4 API error (${res.status}): ${detail}`, res.status, retryAfterSeconds);
|
|
12873
|
+
}
|
|
12874
|
+
return await res.json();
|
|
12875
|
+
}, "report"));
|
|
12705
12876
|
}
|
|
12706
12877
|
async function batchRunReports(accessToken, propertyId, requests) {
|
|
12707
12878
|
const url = `${GA4_DATA_API_BASE}/properties/${propertyId}:batchRunReports`;
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
|
|
12711
|
-
|
|
12712
|
-
|
|
12713
|
-
|
|
12714
|
-
|
|
12715
|
-
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
|
|
12723
|
-
|
|
12724
|
-
|
|
12725
|
-
|
|
12726
|
-
|
|
12727
|
-
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
|
|
12733
|
-
|
|
12734
|
-
|
|
12735
|
-
|
|
12736
|
-
|
|
12879
|
+
return withGa4Limit(() => withGa4Retry(async () => {
|
|
12880
|
+
const res = await fetch(url, {
|
|
12881
|
+
method: "POST",
|
|
12882
|
+
headers: {
|
|
12883
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
12884
|
+
"Content-Type": "application/json"
|
|
12885
|
+
},
|
|
12886
|
+
body: JSON.stringify({ requests }),
|
|
12887
|
+
signal: AbortSignal.timeout(GA4_REQUEST_TIMEOUT_MS)
|
|
12888
|
+
});
|
|
12889
|
+
if (res.status === 401 || res.status === 403) {
|
|
12890
|
+
const body = await res.text().catch(() => "");
|
|
12891
|
+
ga4Log("error", "batch-report.auth-failed", { propertyId, httpStatus: res.status });
|
|
12892
|
+
throw new GA4ApiError(
|
|
12893
|
+
`GA4 API authentication failed \u2014 check service account permissions. ${body}`,
|
|
12894
|
+
res.status
|
|
12895
|
+
);
|
|
12896
|
+
}
|
|
12897
|
+
if (res.status === 429) {
|
|
12898
|
+
const retryAfterSeconds = parseRetryAfter(res.headers.get("retry-after"));
|
|
12899
|
+
ga4Log("error", "batch-report.rate-limited", { propertyId, retryAfterSeconds });
|
|
12900
|
+
throw new GA4ApiError("GA4 API rate limit exceeded", 429, retryAfterSeconds);
|
|
12901
|
+
}
|
|
12902
|
+
if (!res.ok) {
|
|
12903
|
+
const body = await res.text();
|
|
12904
|
+
const retryAfterSeconds = res.status >= 500 ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
|
|
12905
|
+
ga4Log("error", "batch-report.error", { propertyId, httpStatus: res.status, retryAfterSeconds });
|
|
12906
|
+
const detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
|
|
12907
|
+
throw new GA4ApiError(`GA4 API error (${res.status}): ${detail}`, res.status, retryAfterSeconds);
|
|
12908
|
+
}
|
|
12909
|
+
const data = await res.json();
|
|
12910
|
+
return data.reports;
|
|
12911
|
+
}, "batch-report"));
|
|
12737
12912
|
}
|
|
12738
12913
|
function formatDate2(d) {
|
|
12739
12914
|
return d.toISOString().slice(0, 10);
|
|
@@ -17423,7 +17598,7 @@ async function queryBacklinks(opts) {
|
|
|
17423
17598
|
const reversed = opts.targets.map(reverseDomain);
|
|
17424
17599
|
const targetList = reversed.map(quote).join(", ");
|
|
17425
17600
|
const limitClause = opts.limitPerTarget ? `QUALIFY row_number() OVER (PARTITION BY t.target_rev_domain ORDER BY v.num_hosts DESC) <= ${Math.floor(opts.limitPerTarget)}` : "";
|
|
17426
|
-
const
|
|
17601
|
+
const sql17 = `
|
|
17427
17602
|
WITH vertices AS (
|
|
17428
17603
|
SELECT * FROM read_csv(
|
|
17429
17604
|
${quote(opts.vertexPath)},
|
|
@@ -17459,7 +17634,7 @@ async function queryBacklinks(opts) {
|
|
|
17459
17634
|
const conn = await instance.connect();
|
|
17460
17635
|
let rows;
|
|
17461
17636
|
try {
|
|
17462
|
-
const reader = await conn.runAndReadAll(
|
|
17637
|
+
const reader = await conn.runAndReadAll(sql17);
|
|
17463
17638
|
rows = reader.getRowObjects();
|
|
17464
17639
|
} finally {
|
|
17465
17640
|
conn.disconnectSync?.();
|
|
@@ -18131,130 +18306,2384 @@ async function listCloudRunTrafficEvents(accessToken, options) {
|
|
|
18131
18306
|
};
|
|
18132
18307
|
}
|
|
18133
18308
|
|
|
18134
|
-
// ../integration-traffic/src/
|
|
18135
|
-
var
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
|
|
18139
|
-
|
|
18140
|
-
|
|
18141
|
-
|
|
18142
|
-
|
|
18143
|
-
|
|
18144
|
-
|
|
18145
|
-
id: "openai-searchbot",
|
|
18146
|
-
operator: "OpenAI",
|
|
18147
|
-
product: "OAI-SearchBot",
|
|
18148
|
-
purpose: "search",
|
|
18149
|
-
userAgentPatterns: [/OAI-SearchBot\//i]
|
|
18150
|
-
},
|
|
18151
|
-
{
|
|
18152
|
-
id: "openai-chatgpt-user",
|
|
18153
|
-
operator: "OpenAI",
|
|
18154
|
-
product: "ChatGPT-User",
|
|
18155
|
-
purpose: "user-agent",
|
|
18156
|
-
userAgentPatterns: [/ChatGPT-User\//i]
|
|
18157
|
-
},
|
|
18158
|
-
{
|
|
18159
|
-
id: "anthropic-claudebot",
|
|
18160
|
-
operator: "Anthropic",
|
|
18161
|
-
product: "ClaudeBot",
|
|
18162
|
-
purpose: "training",
|
|
18163
|
-
userAgentPatterns: [/ClaudeBot\//i, /Claude-Web\//i, /anthropic-ai/i]
|
|
18164
|
-
},
|
|
18165
|
-
{
|
|
18166
|
-
id: "perplexity-bot",
|
|
18167
|
-
operator: "Perplexity",
|
|
18168
|
-
product: "PerplexityBot",
|
|
18169
|
-
purpose: "search",
|
|
18170
|
-
userAgentPatterns: [/PerplexityBot\//i]
|
|
18171
|
-
},
|
|
18172
|
-
{
|
|
18173
|
-
id: "google-extended",
|
|
18174
|
-
operator: "Google",
|
|
18175
|
-
product: "Google-Extended",
|
|
18176
|
-
purpose: "training-control",
|
|
18177
|
-
userAgentPatterns: [/Google-Extended/i]
|
|
18178
|
-
},
|
|
18179
|
-
{
|
|
18180
|
-
id: "bytespider",
|
|
18181
|
-
operator: "ByteDance",
|
|
18182
|
-
product: "Bytespider",
|
|
18183
|
-
purpose: "training",
|
|
18184
|
-
userAgentPatterns: [/Bytespider/i]
|
|
18185
|
-
},
|
|
18186
|
-
{
|
|
18187
|
-
id: "applebot-extended",
|
|
18188
|
-
operator: "Apple",
|
|
18189
|
-
product: "Applebot-Extended",
|
|
18190
|
-
purpose: "training",
|
|
18191
|
-
userAgentPatterns: [/Applebot-Extended/i]
|
|
18192
|
-
},
|
|
18193
|
-
{
|
|
18194
|
-
id: "meta-externalagent",
|
|
18195
|
-
operator: "Meta",
|
|
18196
|
-
product: "meta-externalagent",
|
|
18197
|
-
purpose: "training",
|
|
18198
|
-
userAgentPatterns: [/meta-externalagent/i]
|
|
18199
|
-
},
|
|
18200
|
-
{
|
|
18201
|
-
id: "ccbot",
|
|
18202
|
-
operator: "Common Crawl",
|
|
18203
|
-
product: "CCBot",
|
|
18204
|
-
purpose: "crawl",
|
|
18205
|
-
userAgentPatterns: [/CCBot\//i]
|
|
18206
|
-
},
|
|
18207
|
-
{
|
|
18208
|
-
id: "cohere-ai",
|
|
18209
|
-
operator: "Cohere",
|
|
18210
|
-
product: "cohere-ai",
|
|
18211
|
-
purpose: "training",
|
|
18212
|
-
userAgentPatterns: [/cohere-ai/i]
|
|
18213
|
-
},
|
|
18214
|
-
{
|
|
18215
|
-
id: "diffbot",
|
|
18216
|
-
operator: "Diffbot",
|
|
18217
|
-
product: "Diffbot",
|
|
18218
|
-
purpose: "crawl",
|
|
18219
|
-
userAgentPatterns: [/Diffbot/i]
|
|
18220
|
-
},
|
|
18221
|
-
{
|
|
18222
|
-
id: "mistral-ai",
|
|
18223
|
-
operator: "Mistral AI",
|
|
18224
|
-
product: "MistralAI-User",
|
|
18225
|
-
purpose: "crawl",
|
|
18226
|
-
userAgentPatterns: [/MistralAI/i]
|
|
18227
|
-
}
|
|
18228
|
-
];
|
|
18229
|
-
var DEFAULT_AI_REFERRER_RULES = [
|
|
18230
|
-
{ domain: AI_ENGINE_DOMAINS.chatgpt, operator: "OpenAI", product: "ChatGPT" },
|
|
18231
|
-
{ domain: LEGACY_CHATGPT_DOMAIN, operator: "OpenAI", product: "ChatGPT" },
|
|
18232
|
-
{ domain: AI_ENGINE_DOMAINS.perplexity, operator: "Perplexity", product: "Perplexity" },
|
|
18233
|
-
{ domain: AI_ENGINE_DOMAINS.claude, operator: "Anthropic", product: "Claude" },
|
|
18234
|
-
{ domain: AI_ENGINE_DOMAINS.gemini, operator: "Google", product: "Gemini" },
|
|
18235
|
-
{ domain: AI_ENGINE_DOMAINS.copilotMicrosoft, operator: "Microsoft", product: "Copilot" },
|
|
18236
|
-
{ domain: AI_ENGINE_DOMAINS.phind, operator: "Phind", product: "Phind" },
|
|
18237
|
-
{ domain: AI_ENGINE_DOMAINS.you, operator: "You.com", product: "You.com" },
|
|
18238
|
-
{ domain: AI_ENGINE_DOMAINS.metaAi, operator: "Meta", product: "Meta AI" }
|
|
18239
|
-
];
|
|
18309
|
+
// ../integration-traffic/src/ip-ranges/anthropic.json
|
|
18310
|
+
var anthropic_default = {
|
|
18311
|
+
_source: "ARIN RDAP \u2014 every network registered to Anthropic, PBC (handle AP-2440)",
|
|
18312
|
+
_query: "https://rdap.arin.net/registry/entity/AP-2440",
|
|
18313
|
+
_notes: "Anthropic does not publish a clean machine-readable IP-range JSON like Google or OpenAI do. These prefixes are taken straight from ARIN's authoritative allocation records (NOT bgp.tools' AS-based view, which can include misleading announcements \u2014 e.g. AS60808 is registered to Anthropic but announces 209.249.57.0/24 which actually belongs to Mitel Networks). 216.73.216.0/22 (AWS-ANTHROPIC) is the load-bearing prefix \u2014 empirical Cloud Run logs show 100% of real ClaudeBot traffic comes from there; the other two are Anthropic's own allocations for non-crawler infra (kept since the verification gate still requires a Claude-* UA match). Refresh by re-running the ARIN RDAP query above and replacing the prefix list.",
|
|
18314
|
+
prefixes: [
|
|
18315
|
+
{ ipv4Prefix: "216.73.216.0/22" },
|
|
18316
|
+
{ ipv4Prefix: "160.79.104.0/21" },
|
|
18317
|
+
{ ipv6Prefix: "2607:6bc0::/32" }
|
|
18318
|
+
]
|
|
18319
|
+
};
|
|
18240
18320
|
|
|
18241
|
-
// ../integration-traffic/src/
|
|
18242
|
-
|
|
18243
|
-
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
|
|
18247
|
-
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18321
|
+
// ../integration-traffic/src/ip-ranges/bingbot.json
|
|
18322
|
+
var bingbot_default = {
|
|
18323
|
+
_source: "https://www.bing.com/toolbox/bingbot.json",
|
|
18324
|
+
creationTime: "2024-01-03T10:00:00.121331",
|
|
18325
|
+
prefixes: [
|
|
18326
|
+
{
|
|
18327
|
+
ipv4Prefix: "157.55.39.0/24"
|
|
18328
|
+
},
|
|
18329
|
+
{
|
|
18330
|
+
ipv4Prefix: "207.46.13.0/24"
|
|
18331
|
+
},
|
|
18332
|
+
{
|
|
18333
|
+
ipv4Prefix: "40.77.167.0/24"
|
|
18334
|
+
},
|
|
18335
|
+
{
|
|
18336
|
+
ipv4Prefix: "13.66.139.0/24"
|
|
18337
|
+
},
|
|
18338
|
+
{
|
|
18339
|
+
ipv4Prefix: "13.66.144.0/24"
|
|
18340
|
+
},
|
|
18341
|
+
{
|
|
18342
|
+
ipv4Prefix: "52.167.144.0/24"
|
|
18343
|
+
},
|
|
18344
|
+
{
|
|
18345
|
+
ipv4Prefix: "13.67.10.16/28"
|
|
18346
|
+
},
|
|
18347
|
+
{
|
|
18348
|
+
ipv4Prefix: "13.69.66.240/28"
|
|
18349
|
+
},
|
|
18350
|
+
{
|
|
18351
|
+
ipv4Prefix: "13.71.172.224/28"
|
|
18352
|
+
},
|
|
18353
|
+
{
|
|
18354
|
+
ipv4Prefix: "139.217.52.0/28"
|
|
18355
|
+
},
|
|
18356
|
+
{
|
|
18357
|
+
ipv4Prefix: "191.233.204.224/28"
|
|
18358
|
+
},
|
|
18359
|
+
{
|
|
18360
|
+
ipv4Prefix: "20.36.108.32/28"
|
|
18361
|
+
},
|
|
18362
|
+
{
|
|
18363
|
+
ipv4Prefix: "20.43.120.16/28"
|
|
18364
|
+
},
|
|
18365
|
+
{
|
|
18366
|
+
ipv4Prefix: "40.79.131.208/28"
|
|
18367
|
+
},
|
|
18368
|
+
{
|
|
18369
|
+
ipv4Prefix: "40.79.186.176/28"
|
|
18370
|
+
},
|
|
18371
|
+
{
|
|
18372
|
+
ipv4Prefix: "52.231.148.0/28"
|
|
18373
|
+
},
|
|
18374
|
+
{
|
|
18375
|
+
ipv4Prefix: "20.79.107.240/28"
|
|
18376
|
+
},
|
|
18377
|
+
{
|
|
18378
|
+
ipv4Prefix: "51.105.67.0/28"
|
|
18379
|
+
},
|
|
18380
|
+
{
|
|
18381
|
+
ipv4Prefix: "20.125.163.80/28"
|
|
18382
|
+
},
|
|
18383
|
+
{
|
|
18384
|
+
ipv4Prefix: "40.77.188.0/22"
|
|
18385
|
+
},
|
|
18386
|
+
{
|
|
18387
|
+
ipv4Prefix: "65.55.210.0/24"
|
|
18388
|
+
},
|
|
18389
|
+
{
|
|
18390
|
+
ipv4Prefix: "199.30.24.0/23"
|
|
18391
|
+
},
|
|
18392
|
+
{
|
|
18393
|
+
ipv4Prefix: "40.77.202.0/24"
|
|
18394
|
+
},
|
|
18395
|
+
{
|
|
18396
|
+
ipv4Prefix: "40.77.139.0/25"
|
|
18397
|
+
},
|
|
18398
|
+
{
|
|
18399
|
+
ipv4Prefix: "20.74.197.0/28"
|
|
18400
|
+
},
|
|
18401
|
+
{
|
|
18402
|
+
ipv4Prefix: "20.15.133.160/27"
|
|
18403
|
+
},
|
|
18404
|
+
{
|
|
18405
|
+
ipv4Prefix: "40.77.177.0/24"
|
|
18406
|
+
},
|
|
18407
|
+
{
|
|
18408
|
+
ipv4Prefix: "40.77.178.0/23"
|
|
18409
|
+
}
|
|
18410
|
+
]
|
|
18411
|
+
};
|
|
18412
|
+
|
|
18413
|
+
// ../integration-traffic/src/ip-ranges/chatgpt-user.json
|
|
18414
|
+
var chatgpt_user_default = {
|
|
18415
|
+
_source: "https://openai.com/chatgpt-user.json",
|
|
18416
|
+
creationTime: "2026-05-17T23:03:25.747192",
|
|
18417
|
+
prefixes: [
|
|
18418
|
+
{
|
|
18419
|
+
ipv4Prefix: "104.210.139.192/28"
|
|
18420
|
+
},
|
|
18421
|
+
{
|
|
18422
|
+
ipv4Prefix: "104.210.139.224/28"
|
|
18423
|
+
},
|
|
18424
|
+
{
|
|
18425
|
+
ipv4Prefix: "13.65.138.112/28"
|
|
18426
|
+
},
|
|
18427
|
+
{
|
|
18428
|
+
ipv4Prefix: "13.65.138.96/28"
|
|
18429
|
+
},
|
|
18430
|
+
{
|
|
18431
|
+
ipv4Prefix: "13.67.72.16/28"
|
|
18432
|
+
},
|
|
18433
|
+
{
|
|
18434
|
+
ipv4Prefix: "13.70.107.160/28"
|
|
18435
|
+
},
|
|
18436
|
+
{
|
|
18437
|
+
ipv4Prefix: "13.71.2.208/28"
|
|
18438
|
+
},
|
|
18439
|
+
{
|
|
18440
|
+
ipv4Prefix: "13.76.115.224/28"
|
|
18441
|
+
},
|
|
18442
|
+
{
|
|
18443
|
+
ipv4Prefix: "13.76.115.240/28"
|
|
18444
|
+
},
|
|
18445
|
+
{
|
|
18446
|
+
ipv4Prefix: "13.76.116.80/28"
|
|
18447
|
+
},
|
|
18448
|
+
{
|
|
18449
|
+
ipv4Prefix: "13.76.32.208/28"
|
|
18450
|
+
},
|
|
18451
|
+
{
|
|
18452
|
+
ipv4Prefix: "13.83.167.128/28"
|
|
18453
|
+
},
|
|
18454
|
+
{
|
|
18455
|
+
ipv4Prefix: "13.83.237.176/28"
|
|
18456
|
+
},
|
|
18457
|
+
{
|
|
18458
|
+
ipv4Prefix: "132.196.82.48/28"
|
|
18459
|
+
},
|
|
18460
|
+
{
|
|
18461
|
+
ipv4Prefix: "135.119.134.128/28"
|
|
18462
|
+
},
|
|
18463
|
+
{
|
|
18464
|
+
ipv4Prefix: "135.119.134.192/28"
|
|
18465
|
+
},
|
|
18466
|
+
{
|
|
18467
|
+
ipv4Prefix: "135.220.73.208/28"
|
|
18468
|
+
},
|
|
18469
|
+
{
|
|
18470
|
+
ipv4Prefix: "135.220.73.240/28"
|
|
18471
|
+
},
|
|
18472
|
+
{
|
|
18473
|
+
ipv4Prefix: "135.237.131.208/28"
|
|
18474
|
+
},
|
|
18475
|
+
{
|
|
18476
|
+
ipv4Prefix: "135.237.133.48/28"
|
|
18477
|
+
},
|
|
18478
|
+
{
|
|
18479
|
+
ipv4Prefix: "137.135.191.176/28"
|
|
18480
|
+
},
|
|
18481
|
+
{
|
|
18482
|
+
ipv4Prefix: "138.91.30.48/28"
|
|
18483
|
+
},
|
|
18484
|
+
{
|
|
18485
|
+
ipv4Prefix: "138.91.46.96/28"
|
|
18486
|
+
},
|
|
18487
|
+
{
|
|
18488
|
+
ipv4Prefix: "168.63.252.240/28"
|
|
18489
|
+
},
|
|
18490
|
+
{
|
|
18491
|
+
ipv4Prefix: "172.170.8.208/28"
|
|
18492
|
+
},
|
|
18493
|
+
{
|
|
18494
|
+
ipv4Prefix: "172.171.4.176/28"
|
|
18495
|
+
},
|
|
18496
|
+
{
|
|
18497
|
+
ipv4Prefix: "172.178.140.144/28"
|
|
18498
|
+
},
|
|
18499
|
+
{
|
|
18500
|
+
ipv4Prefix: "172.178.141.112/28"
|
|
18501
|
+
},
|
|
18502
|
+
{
|
|
18503
|
+
ipv4Prefix: "172.178.141.128/28"
|
|
18504
|
+
},
|
|
18505
|
+
{
|
|
18506
|
+
ipv4Prefix: "172.183.143.224/28"
|
|
18507
|
+
},
|
|
18508
|
+
{
|
|
18509
|
+
ipv4Prefix: "172.183.222.128/28"
|
|
18510
|
+
},
|
|
18511
|
+
{
|
|
18512
|
+
ipv4Prefix: "172.196.40.208/28"
|
|
18513
|
+
},
|
|
18514
|
+
{
|
|
18515
|
+
ipv4Prefix: "172.202.102.112/28"
|
|
18516
|
+
},
|
|
18517
|
+
{
|
|
18518
|
+
ipv4Prefix: "172.204.16.64/28"
|
|
18519
|
+
},
|
|
18520
|
+
{
|
|
18521
|
+
ipv4Prefix: "172.204.27.16/28"
|
|
18522
|
+
},
|
|
18523
|
+
{
|
|
18524
|
+
ipv4Prefix: "172.212.159.64/28"
|
|
18525
|
+
},
|
|
18526
|
+
{
|
|
18527
|
+
ipv4Prefix: "172.212.172.160/28"
|
|
18528
|
+
},
|
|
18529
|
+
{
|
|
18530
|
+
ipv4Prefix: "172.213.11.144/28"
|
|
18531
|
+
},
|
|
18532
|
+
{
|
|
18533
|
+
ipv4Prefix: "172.213.12.112/28"
|
|
18534
|
+
},
|
|
18535
|
+
{
|
|
18536
|
+
ipv4Prefix: "172.213.21.112/28"
|
|
18537
|
+
},
|
|
18538
|
+
{
|
|
18539
|
+
ipv4Prefix: "172.213.21.144/28"
|
|
18540
|
+
},
|
|
18541
|
+
{
|
|
18542
|
+
ipv4Prefix: "172.213.21.16/28"
|
|
18543
|
+
},
|
|
18544
|
+
{
|
|
18545
|
+
ipv4Prefix: "172.215.218.96/28"
|
|
18546
|
+
},
|
|
18547
|
+
{
|
|
18548
|
+
ipv4Prefix: "191.233.1.112/28"
|
|
18549
|
+
},
|
|
18550
|
+
{
|
|
18551
|
+
ipv4Prefix: "191.233.1.128/28"
|
|
18552
|
+
},
|
|
18553
|
+
{
|
|
18554
|
+
ipv4Prefix: "191.233.1.224/28"
|
|
18555
|
+
},
|
|
18556
|
+
{
|
|
18557
|
+
ipv4Prefix: "191.233.194.32/28"
|
|
18558
|
+
},
|
|
18559
|
+
{
|
|
18560
|
+
ipv4Prefix: "191.233.196.112/28"
|
|
18561
|
+
},
|
|
18562
|
+
{
|
|
18563
|
+
ipv4Prefix: "191.233.199.160/28"
|
|
18564
|
+
},
|
|
18565
|
+
{
|
|
18566
|
+
ipv4Prefix: "191.233.2.0/28"
|
|
18567
|
+
},
|
|
18568
|
+
{
|
|
18569
|
+
ipv4Prefix: "191.234.167.128/28"
|
|
18570
|
+
},
|
|
18571
|
+
{
|
|
18572
|
+
ipv4Prefix: "191.235.66.16/28"
|
|
18573
|
+
},
|
|
18574
|
+
{
|
|
18575
|
+
ipv4Prefix: "191.235.98.144/28"
|
|
18576
|
+
},
|
|
18577
|
+
{
|
|
18578
|
+
ipv4Prefix: "191.235.99.80/28"
|
|
18579
|
+
},
|
|
18580
|
+
{
|
|
18581
|
+
ipv4Prefix: "191.237.249.64/28"
|
|
18582
|
+
},
|
|
18583
|
+
{
|
|
18584
|
+
ipv4Prefix: "191.239.245.16/28"
|
|
18585
|
+
},
|
|
18586
|
+
{
|
|
18587
|
+
ipv4Prefix: "20.0.53.96/28"
|
|
18588
|
+
},
|
|
18589
|
+
{
|
|
18590
|
+
ipv4Prefix: "20.102.212.144/28"
|
|
18591
|
+
},
|
|
18592
|
+
{
|
|
18593
|
+
ipv4Prefix: "20.113.218.16/28"
|
|
18594
|
+
},
|
|
18595
|
+
{
|
|
18596
|
+
ipv4Prefix: "20.113.225.112/28"
|
|
18597
|
+
},
|
|
18598
|
+
{
|
|
18599
|
+
ipv4Prefix: "20.125.112.224/28"
|
|
18600
|
+
},
|
|
18601
|
+
{
|
|
18602
|
+
ipv4Prefix: "20.125.144.144/28"
|
|
18603
|
+
},
|
|
18604
|
+
{
|
|
18605
|
+
ipv4Prefix: "20.161.75.208/28"
|
|
18606
|
+
},
|
|
18607
|
+
{
|
|
18608
|
+
ipv4Prefix: "20.168.7.192/28"
|
|
18609
|
+
},
|
|
18610
|
+
{
|
|
18611
|
+
ipv4Prefix: "20.168.7.240/28"
|
|
18612
|
+
},
|
|
18613
|
+
{
|
|
18614
|
+
ipv4Prefix: "20.169.72.112/28"
|
|
18615
|
+
},
|
|
18616
|
+
{
|
|
18617
|
+
ipv4Prefix: "20.169.72.96/28"
|
|
18618
|
+
},
|
|
18619
|
+
{
|
|
18620
|
+
ipv4Prefix: "20.169.73.176/28"
|
|
18621
|
+
},
|
|
18622
|
+
{
|
|
18623
|
+
ipv4Prefix: "20.169.73.32/28"
|
|
18624
|
+
},
|
|
18625
|
+
{
|
|
18626
|
+
ipv4Prefix: "20.169.73.64/28"
|
|
18627
|
+
},
|
|
18628
|
+
{
|
|
18629
|
+
ipv4Prefix: "20.169.78.112/28"
|
|
18630
|
+
},
|
|
18631
|
+
{
|
|
18632
|
+
ipv4Prefix: "20.169.78.128/28"
|
|
18633
|
+
},
|
|
18634
|
+
{
|
|
18635
|
+
ipv4Prefix: "20.169.78.144/28"
|
|
18636
|
+
},
|
|
18637
|
+
{
|
|
18638
|
+
ipv4Prefix: "20.169.78.160/28"
|
|
18639
|
+
},
|
|
18640
|
+
{
|
|
18641
|
+
ipv4Prefix: "20.169.78.176/28"
|
|
18642
|
+
},
|
|
18643
|
+
{
|
|
18644
|
+
ipv4Prefix: "20.169.78.192/28"
|
|
18645
|
+
},
|
|
18646
|
+
{
|
|
18647
|
+
ipv4Prefix: "20.169.78.208/28"
|
|
18648
|
+
},
|
|
18649
|
+
{
|
|
18650
|
+
ipv4Prefix: "20.169.78.48/28"
|
|
18651
|
+
},
|
|
18652
|
+
{
|
|
18653
|
+
ipv4Prefix: "20.169.78.64/28"
|
|
18654
|
+
},
|
|
18655
|
+
{
|
|
18656
|
+
ipv4Prefix: "20.169.78.80/28"
|
|
18657
|
+
},
|
|
18658
|
+
{
|
|
18659
|
+
ipv4Prefix: "20.169.78.96/28"
|
|
18660
|
+
},
|
|
18661
|
+
{
|
|
18662
|
+
ipv4Prefix: "20.169.86.224/28"
|
|
18663
|
+
},
|
|
18664
|
+
{
|
|
18665
|
+
ipv4Prefix: "20.169.86.240/28"
|
|
18666
|
+
},
|
|
18667
|
+
{
|
|
18668
|
+
ipv4Prefix: "20.169.87.112/28"
|
|
18669
|
+
},
|
|
18670
|
+
{
|
|
18671
|
+
ipv4Prefix: "20.17.108.96/28"
|
|
18672
|
+
},
|
|
18673
|
+
{
|
|
18674
|
+
ipv4Prefix: "20.172.29.32/28"
|
|
18675
|
+
},
|
|
18676
|
+
{
|
|
18677
|
+
ipv4Prefix: "20.193.233.240/28"
|
|
18678
|
+
},
|
|
18679
|
+
{
|
|
18680
|
+
ipv4Prefix: "20.193.50.32/28"
|
|
18681
|
+
},
|
|
18682
|
+
{
|
|
18683
|
+
ipv4Prefix: "20.194.0.208/28"
|
|
18684
|
+
},
|
|
18685
|
+
{
|
|
18686
|
+
ipv4Prefix: "20.194.1.0/28"
|
|
18687
|
+
},
|
|
18688
|
+
{
|
|
18689
|
+
ipv4Prefix: "20.194.157.176/28"
|
|
18690
|
+
},
|
|
18691
|
+
{
|
|
18692
|
+
ipv4Prefix: "20.198.67.96/28"
|
|
18693
|
+
},
|
|
18694
|
+
{
|
|
18695
|
+
ipv4Prefix: "20.199.211.160/28"
|
|
18696
|
+
},
|
|
18697
|
+
{
|
|
18698
|
+
ipv4Prefix: "20.203.245.32/28"
|
|
18699
|
+
},
|
|
18700
|
+
{
|
|
18701
|
+
ipv4Prefix: "20.204.24.240/28"
|
|
18702
|
+
},
|
|
18703
|
+
{
|
|
18704
|
+
ipv4Prefix: "20.206.107.192/28"
|
|
18705
|
+
},
|
|
18706
|
+
{
|
|
18707
|
+
ipv4Prefix: "20.210.154.128/28"
|
|
18708
|
+
},
|
|
18709
|
+
{
|
|
18710
|
+
ipv4Prefix: "20.210.174.208/28"
|
|
18711
|
+
},
|
|
18712
|
+
{
|
|
18713
|
+
ipv4Prefix: "20.210.211.192/28"
|
|
18714
|
+
},
|
|
18715
|
+
{
|
|
18716
|
+
ipv4Prefix: "20.215.187.208/28"
|
|
18717
|
+
},
|
|
18718
|
+
{
|
|
18719
|
+
ipv4Prefix: "20.215.188.192/28"
|
|
18720
|
+
},
|
|
18721
|
+
{
|
|
18722
|
+
ipv4Prefix: "20.215.214.16/28"
|
|
18723
|
+
},
|
|
18724
|
+
{
|
|
18725
|
+
ipv4Prefix: "20.215.219.128/28"
|
|
18726
|
+
},
|
|
18727
|
+
{
|
|
18728
|
+
ipv4Prefix: "20.215.219.160/28"
|
|
18729
|
+
},
|
|
18730
|
+
{
|
|
18731
|
+
ipv4Prefix: "20.215.219.208/28"
|
|
18732
|
+
},
|
|
18733
|
+
{
|
|
18734
|
+
ipv4Prefix: "20.215.220.112/28"
|
|
18735
|
+
},
|
|
18736
|
+
{
|
|
18737
|
+
ipv4Prefix: "20.215.220.128/28"
|
|
18738
|
+
},
|
|
18739
|
+
{
|
|
18740
|
+
ipv4Prefix: "20.215.220.144/28"
|
|
18741
|
+
},
|
|
18742
|
+
{
|
|
18743
|
+
ipv4Prefix: "20.215.220.160/28"
|
|
18744
|
+
},
|
|
18745
|
+
{
|
|
18746
|
+
ipv4Prefix: "20.215.220.176/28"
|
|
18747
|
+
},
|
|
18748
|
+
{
|
|
18749
|
+
ipv4Prefix: "20.215.220.192/28"
|
|
18750
|
+
},
|
|
18751
|
+
{
|
|
18752
|
+
ipv4Prefix: "20.215.220.208/28"
|
|
18753
|
+
},
|
|
18754
|
+
{
|
|
18755
|
+
ipv4Prefix: "20.215.220.64/28"
|
|
18756
|
+
},
|
|
18757
|
+
{
|
|
18758
|
+
ipv4Prefix: "20.215.220.80/28"
|
|
18759
|
+
},
|
|
18760
|
+
{
|
|
18761
|
+
ipv4Prefix: "20.215.220.96/28"
|
|
18762
|
+
},
|
|
18763
|
+
{
|
|
18764
|
+
ipv4Prefix: "20.226.32.80/28"
|
|
18765
|
+
},
|
|
18766
|
+
{
|
|
18767
|
+
ipv4Prefix: "20.227.140.32/28"
|
|
18768
|
+
},
|
|
18769
|
+
{
|
|
18770
|
+
ipv4Prefix: "20.228.106.176/28"
|
|
18771
|
+
},
|
|
18772
|
+
{
|
|
18773
|
+
ipv4Prefix: "20.235.75.208/28"
|
|
18774
|
+
},
|
|
18775
|
+
{
|
|
18776
|
+
ipv4Prefix: "20.235.87.224/28"
|
|
18777
|
+
},
|
|
18778
|
+
{
|
|
18779
|
+
ipv4Prefix: "20.249.63.208/28"
|
|
18780
|
+
},
|
|
18781
|
+
{
|
|
18782
|
+
ipv4Prefix: "20.27.94.128/28"
|
|
18783
|
+
},
|
|
18784
|
+
{
|
|
18785
|
+
ipv4Prefix: "20.42.250.32/28"
|
|
18786
|
+
},
|
|
18787
|
+
{
|
|
18788
|
+
ipv4Prefix: "20.45.178.144/28"
|
|
18789
|
+
},
|
|
18790
|
+
{
|
|
18791
|
+
ipv4Prefix: "20.55.229.144/28"
|
|
18792
|
+
},
|
|
18793
|
+
{
|
|
18794
|
+
ipv4Prefix: "20.57.199.192/28"
|
|
18795
|
+
},
|
|
18796
|
+
{
|
|
18797
|
+
ipv4Prefix: "20.63.221.64/28"
|
|
18798
|
+
},
|
|
18799
|
+
{
|
|
18800
|
+
ipv4Prefix: "20.97.189.96/28"
|
|
18801
|
+
},
|
|
18802
|
+
{
|
|
18803
|
+
ipv4Prefix: "23.102.140.144/28"
|
|
18804
|
+
},
|
|
18805
|
+
{
|
|
18806
|
+
ipv4Prefix: "23.102.141.32/28"
|
|
18807
|
+
},
|
|
18808
|
+
{
|
|
18809
|
+
ipv4Prefix: "23.97.109.224/28"
|
|
18810
|
+
},
|
|
18811
|
+
{
|
|
18812
|
+
ipv4Prefix: "23.98.142.176/28"
|
|
18813
|
+
},
|
|
18814
|
+
{
|
|
18815
|
+
ipv4Prefix: "23.98.179.16/28"
|
|
18816
|
+
},
|
|
18817
|
+
{
|
|
18818
|
+
ipv4Prefix: "23.98.186.176/28"
|
|
18819
|
+
},
|
|
18820
|
+
{
|
|
18821
|
+
ipv4Prefix: "23.98.186.192/28"
|
|
18822
|
+
},
|
|
18823
|
+
{
|
|
18824
|
+
ipv4Prefix: "23.98.186.64/28"
|
|
18825
|
+
},
|
|
18826
|
+
{
|
|
18827
|
+
ipv4Prefix: "23.98.186.96/28"
|
|
18828
|
+
},
|
|
18829
|
+
{
|
|
18830
|
+
ipv4Prefix: "4.151.119.48/28"
|
|
18831
|
+
},
|
|
18832
|
+
{
|
|
18833
|
+
ipv4Prefix: "4.151.241.240/28"
|
|
18834
|
+
},
|
|
18835
|
+
{
|
|
18836
|
+
ipv4Prefix: "4.151.71.176/28"
|
|
18837
|
+
},
|
|
18838
|
+
{
|
|
18839
|
+
ipv4Prefix: "4.189.118.208/28"
|
|
18840
|
+
},
|
|
18841
|
+
{
|
|
18842
|
+
ipv4Prefix: "4.189.119.48/28"
|
|
18843
|
+
},
|
|
18844
|
+
{
|
|
18845
|
+
ipv4Prefix: "4.196.118.112/28"
|
|
18846
|
+
},
|
|
18847
|
+
{
|
|
18848
|
+
ipv4Prefix: "4.196.198.80/28"
|
|
18849
|
+
},
|
|
18850
|
+
{
|
|
18851
|
+
ipv4Prefix: "4.197.115.112/28"
|
|
18852
|
+
},
|
|
18853
|
+
{
|
|
18854
|
+
ipv4Prefix: "4.197.19.176/28"
|
|
18855
|
+
},
|
|
18856
|
+
{
|
|
18857
|
+
ipv4Prefix: "4.197.22.112/28"
|
|
18858
|
+
},
|
|
18859
|
+
{
|
|
18860
|
+
ipv4Prefix: "4.197.64.0/28"
|
|
18861
|
+
},
|
|
18862
|
+
{
|
|
18863
|
+
ipv4Prefix: "4.197.64.16/28"
|
|
18864
|
+
},
|
|
18865
|
+
{
|
|
18866
|
+
ipv4Prefix: "4.197.64.48/28"
|
|
18867
|
+
},
|
|
18868
|
+
{
|
|
18869
|
+
ipv4Prefix: "4.197.64.64/28"
|
|
18870
|
+
},
|
|
18871
|
+
{
|
|
18872
|
+
ipv4Prefix: "4.198.72.16/28"
|
|
18873
|
+
},
|
|
18874
|
+
{
|
|
18875
|
+
ipv4Prefix: "4.205.128.176/28"
|
|
18876
|
+
},
|
|
18877
|
+
{
|
|
18878
|
+
ipv4Prefix: "4.226.226.32/28"
|
|
18879
|
+
},
|
|
18880
|
+
{
|
|
18881
|
+
ipv4Prefix: "40.116.73.208/28"
|
|
18882
|
+
},
|
|
18883
|
+
{
|
|
18884
|
+
ipv4Prefix: "40.122.235.112/28"
|
|
18885
|
+
},
|
|
18886
|
+
{
|
|
18887
|
+
ipv4Prefix: "40.67.183.160/28"
|
|
18888
|
+
},
|
|
18889
|
+
{
|
|
18890
|
+
ipv4Prefix: "40.67.183.176/28"
|
|
18891
|
+
},
|
|
18892
|
+
{
|
|
18893
|
+
ipv4Prefix: "40.75.14.224/28"
|
|
18894
|
+
},
|
|
18895
|
+
{
|
|
18896
|
+
ipv4Prefix: "40.81.134.128/28"
|
|
18897
|
+
},
|
|
18898
|
+
{
|
|
18899
|
+
ipv4Prefix: "40.81.134.144/28"
|
|
18900
|
+
},
|
|
18901
|
+
{
|
|
18902
|
+
ipv4Prefix: "40.81.234.144/28"
|
|
18903
|
+
},
|
|
18904
|
+
{
|
|
18905
|
+
ipv4Prefix: "40.84.181.32/28"
|
|
18906
|
+
},
|
|
18907
|
+
{
|
|
18908
|
+
ipv4Prefix: "40.84.221.208/28"
|
|
18909
|
+
},
|
|
18910
|
+
{
|
|
18911
|
+
ipv4Prefix: "40.84.221.224/28"
|
|
18912
|
+
},
|
|
18913
|
+
{
|
|
18914
|
+
ipv4Prefix: "48.193.44.32/28"
|
|
18915
|
+
},
|
|
18916
|
+
{
|
|
18917
|
+
ipv4Prefix: "51.107.70.192/28"
|
|
18918
|
+
},
|
|
18919
|
+
{
|
|
18920
|
+
ipv4Prefix: "51.116.2.64/28"
|
|
18921
|
+
},
|
|
18922
|
+
{
|
|
18923
|
+
ipv4Prefix: "51.116.2.80/28"
|
|
18924
|
+
},
|
|
18925
|
+
{
|
|
18926
|
+
ipv4Prefix: "51.8.155.48/28"
|
|
18927
|
+
},
|
|
18928
|
+
{
|
|
18929
|
+
ipv4Prefix: "51.8.155.64/28"
|
|
18930
|
+
},
|
|
18931
|
+
{
|
|
18932
|
+
ipv4Prefix: "51.8.155.80/28"
|
|
18933
|
+
},
|
|
18934
|
+
{
|
|
18935
|
+
ipv4Prefix: "52.148.129.32/28"
|
|
18936
|
+
},
|
|
18937
|
+
{
|
|
18938
|
+
ipv4Prefix: "52.153.130.48/28"
|
|
18939
|
+
},
|
|
18940
|
+
{
|
|
18941
|
+
ipv4Prefix: "52.153.130.64/28"
|
|
18942
|
+
},
|
|
18943
|
+
{
|
|
18944
|
+
ipv4Prefix: "52.154.22.48/28"
|
|
18945
|
+
},
|
|
18946
|
+
{
|
|
18947
|
+
ipv4Prefix: "52.156.77.144/28"
|
|
18948
|
+
},
|
|
18949
|
+
{
|
|
18950
|
+
ipv4Prefix: "52.159.227.32/28"
|
|
18951
|
+
},
|
|
18952
|
+
{
|
|
18953
|
+
ipv4Prefix: "52.159.249.96/28"
|
|
18954
|
+
},
|
|
18955
|
+
{
|
|
18956
|
+
ipv4Prefix: "52.165.212.16/28"
|
|
18957
|
+
},
|
|
18958
|
+
{
|
|
18959
|
+
ipv4Prefix: "52.165.212.32/28"
|
|
18960
|
+
},
|
|
18961
|
+
{
|
|
18962
|
+
ipv4Prefix: "52.165.212.48/28"
|
|
18963
|
+
},
|
|
18964
|
+
{
|
|
18965
|
+
ipv4Prefix: "52.172.129.160/28"
|
|
18966
|
+
},
|
|
18967
|
+
{
|
|
18968
|
+
ipv4Prefix: "52.172.251.112/28"
|
|
18969
|
+
},
|
|
18970
|
+
{
|
|
18971
|
+
ipv4Prefix: "52.173.123.0/28"
|
|
18972
|
+
},
|
|
18973
|
+
{
|
|
18974
|
+
ipv4Prefix: "52.173.219.112/28"
|
|
18975
|
+
},
|
|
18976
|
+
{
|
|
18977
|
+
ipv4Prefix: "52.173.219.96/28"
|
|
18978
|
+
},
|
|
18979
|
+
{
|
|
18980
|
+
ipv4Prefix: "52.173.221.16/28"
|
|
18981
|
+
},
|
|
18982
|
+
{
|
|
18983
|
+
ipv4Prefix: "52.173.221.176/28"
|
|
18984
|
+
},
|
|
18985
|
+
{
|
|
18986
|
+
ipv4Prefix: "52.173.221.208/28"
|
|
18987
|
+
},
|
|
18988
|
+
{
|
|
18989
|
+
ipv4Prefix: "52.173.234.16/28"
|
|
18990
|
+
},
|
|
18991
|
+
{
|
|
18992
|
+
ipv4Prefix: "52.173.234.80/28"
|
|
18993
|
+
},
|
|
18994
|
+
{
|
|
18995
|
+
ipv4Prefix: "52.173.235.80/28"
|
|
18996
|
+
},
|
|
18997
|
+
{
|
|
18998
|
+
ipv4Prefix: "52.176.139.176/28"
|
|
18999
|
+
},
|
|
19000
|
+
{
|
|
19001
|
+
ipv4Prefix: "52.187.246.128/28"
|
|
19002
|
+
},
|
|
19003
|
+
{
|
|
19004
|
+
ipv4Prefix: "52.190.137.144/28"
|
|
19005
|
+
},
|
|
19006
|
+
{
|
|
19007
|
+
ipv4Prefix: "52.190.137.16/28"
|
|
19008
|
+
},
|
|
19009
|
+
{
|
|
19010
|
+
ipv4Prefix: "52.190.139.48/28"
|
|
19011
|
+
},
|
|
19012
|
+
{
|
|
19013
|
+
ipv4Prefix: "52.190.142.64/28"
|
|
19014
|
+
},
|
|
19015
|
+
{
|
|
19016
|
+
ipv4Prefix: "52.190.190.16/28"
|
|
19017
|
+
},
|
|
19018
|
+
{
|
|
19019
|
+
ipv4Prefix: "52.225.75.208/28"
|
|
19020
|
+
},
|
|
19021
|
+
{
|
|
19022
|
+
ipv4Prefix: "52.230.163.32/28"
|
|
19023
|
+
},
|
|
19024
|
+
{
|
|
19025
|
+
ipv4Prefix: "52.230.164.176/28"
|
|
19026
|
+
},
|
|
19027
|
+
{
|
|
19028
|
+
ipv4Prefix: "52.231.30.48/28"
|
|
19029
|
+
},
|
|
19030
|
+
{
|
|
19031
|
+
ipv4Prefix: "52.231.34.176/28"
|
|
19032
|
+
},
|
|
19033
|
+
{
|
|
19034
|
+
ipv4Prefix: "52.231.39.144/28"
|
|
19035
|
+
},
|
|
19036
|
+
{
|
|
19037
|
+
ipv4Prefix: "52.231.39.192/28"
|
|
19038
|
+
},
|
|
19039
|
+
{
|
|
19040
|
+
ipv4Prefix: "52.231.49.48/28"
|
|
19041
|
+
},
|
|
19042
|
+
{
|
|
19043
|
+
ipv4Prefix: "52.231.50.64/28"
|
|
19044
|
+
},
|
|
19045
|
+
{
|
|
19046
|
+
ipv4Prefix: "52.236.94.144/28"
|
|
19047
|
+
},
|
|
19048
|
+
{
|
|
19049
|
+
ipv4Prefix: "52.241.146.208/28"
|
|
19050
|
+
},
|
|
19051
|
+
{
|
|
19052
|
+
ipv4Prefix: "52.242.132.224/28"
|
|
19053
|
+
},
|
|
19054
|
+
{
|
|
19055
|
+
ipv4Prefix: "52.242.132.240/28"
|
|
19056
|
+
},
|
|
19057
|
+
{
|
|
19058
|
+
ipv4Prefix: "52.242.245.208/28"
|
|
19059
|
+
},
|
|
19060
|
+
{
|
|
19061
|
+
ipv4Prefix: "52.252.113.240/28"
|
|
19062
|
+
},
|
|
19063
|
+
{
|
|
19064
|
+
ipv4Prefix: "52.255.109.112/28"
|
|
19065
|
+
},
|
|
19066
|
+
{
|
|
19067
|
+
ipv4Prefix: "52.255.109.128/28"
|
|
19068
|
+
},
|
|
19069
|
+
{
|
|
19070
|
+
ipv4Prefix: "52.255.109.144/28"
|
|
19071
|
+
},
|
|
19072
|
+
{
|
|
19073
|
+
ipv4Prefix: "52.255.109.80/28"
|
|
19074
|
+
},
|
|
19075
|
+
{
|
|
19076
|
+
ipv4Prefix: "52.255.109.96/28"
|
|
19077
|
+
},
|
|
19078
|
+
{
|
|
19079
|
+
ipv4Prefix: "52.255.111.0/28"
|
|
19080
|
+
},
|
|
19081
|
+
{
|
|
19082
|
+
ipv4Prefix: "52.255.111.112/28"
|
|
19083
|
+
},
|
|
19084
|
+
{
|
|
19085
|
+
ipv4Prefix: "52.255.111.16/28"
|
|
19086
|
+
},
|
|
19087
|
+
{
|
|
19088
|
+
ipv4Prefix: "52.255.111.32/28"
|
|
19089
|
+
},
|
|
19090
|
+
{
|
|
19091
|
+
ipv4Prefix: "52.255.111.48/28"
|
|
19092
|
+
},
|
|
19093
|
+
{
|
|
19094
|
+
ipv4Prefix: "52.255.111.80/28"
|
|
19095
|
+
},
|
|
19096
|
+
{
|
|
19097
|
+
ipv4Prefix: "57.151.131.224/28"
|
|
19098
|
+
},
|
|
19099
|
+
{
|
|
19100
|
+
ipv4Prefix: "57.154.174.112/28"
|
|
19101
|
+
},
|
|
19102
|
+
{
|
|
19103
|
+
ipv4Prefix: "57.154.175.0/28"
|
|
19104
|
+
},
|
|
19105
|
+
{
|
|
19106
|
+
ipv4Prefix: "57.154.187.32/28"
|
|
19107
|
+
},
|
|
19108
|
+
{
|
|
19109
|
+
ipv4Prefix: "68.154.28.96/28"
|
|
19110
|
+
},
|
|
19111
|
+
{
|
|
19112
|
+
ipv4Prefix: "68.218.30.112/28"
|
|
19113
|
+
},
|
|
19114
|
+
{
|
|
19115
|
+
ipv4Prefix: "68.220.57.64/28"
|
|
19116
|
+
},
|
|
19117
|
+
{
|
|
19118
|
+
ipv4Prefix: "68.221.67.160/28"
|
|
19119
|
+
},
|
|
19120
|
+
{
|
|
19121
|
+
ipv4Prefix: "68.221.67.192/28"
|
|
19122
|
+
},
|
|
19123
|
+
{
|
|
19124
|
+
ipv4Prefix: "68.221.67.224/28"
|
|
19125
|
+
},
|
|
19126
|
+
{
|
|
19127
|
+
ipv4Prefix: "68.221.67.240/28"
|
|
19128
|
+
},
|
|
19129
|
+
{
|
|
19130
|
+
ipv4Prefix: "68.221.75.16/28"
|
|
19131
|
+
},
|
|
19132
|
+
{
|
|
19133
|
+
ipv4Prefix: "70.153.76.16/28"
|
|
19134
|
+
},
|
|
19135
|
+
{
|
|
19136
|
+
ipv4Prefix: "74.226.253.160/28"
|
|
19137
|
+
},
|
|
19138
|
+
{
|
|
19139
|
+
ipv4Prefix: "74.249.86.176/28"
|
|
19140
|
+
},
|
|
19141
|
+
{
|
|
19142
|
+
ipv4Prefix: "74.7.35.112/28"
|
|
19143
|
+
},
|
|
19144
|
+
{
|
|
19145
|
+
ipv4Prefix: "74.7.35.48/28"
|
|
19146
|
+
},
|
|
19147
|
+
{
|
|
19148
|
+
ipv4Prefix: "74.7.36.64/28"
|
|
19149
|
+
},
|
|
19150
|
+
{
|
|
19151
|
+
ipv4Prefix: "74.7.36.80/28"
|
|
19152
|
+
},
|
|
19153
|
+
{
|
|
19154
|
+
ipv4Prefix: "74.7.36.96/28"
|
|
19155
|
+
},
|
|
19156
|
+
{
|
|
19157
|
+
ipv4Prefix: "85.211.241.128/28"
|
|
19158
|
+
},
|
|
19159
|
+
{
|
|
19160
|
+
ipv4Prefix: "9.160.163.224/28"
|
|
19161
|
+
},
|
|
19162
|
+
{
|
|
19163
|
+
ipv4Prefix: "9.160.164.128/28"
|
|
19164
|
+
},
|
|
19165
|
+
{
|
|
19166
|
+
ipv4Prefix: "9.234.96.192/28"
|
|
19167
|
+
}
|
|
19168
|
+
]
|
|
19169
|
+
};
|
|
19170
|
+
|
|
19171
|
+
// ../integration-traffic/src/ip-ranges/googlebot.json
|
|
19172
|
+
var googlebot_default = {
|
|
19173
|
+
_source: "https://developers.google.com/static/search/apis/ipranges/googlebot.json",
|
|
19174
|
+
creationTime: "2026-05-18T14:46:14.000000",
|
|
19175
|
+
prefixes: [
|
|
19176
|
+
{
|
|
19177
|
+
ipv6Prefix: "2001:4860:4801:10::/64"
|
|
19178
|
+
},
|
|
19179
|
+
{
|
|
19180
|
+
ipv6Prefix: "2001:4860:4801:11::/64"
|
|
19181
|
+
},
|
|
19182
|
+
{
|
|
19183
|
+
ipv6Prefix: "2001:4860:4801:12::/64"
|
|
19184
|
+
},
|
|
19185
|
+
{
|
|
19186
|
+
ipv6Prefix: "2001:4860:4801:13::/64"
|
|
19187
|
+
},
|
|
19188
|
+
{
|
|
19189
|
+
ipv6Prefix: "2001:4860:4801:14::/64"
|
|
19190
|
+
},
|
|
19191
|
+
{
|
|
19192
|
+
ipv6Prefix: "2001:4860:4801:15::/64"
|
|
19193
|
+
},
|
|
19194
|
+
{
|
|
19195
|
+
ipv6Prefix: "2001:4860:4801:16::/64"
|
|
19196
|
+
},
|
|
19197
|
+
{
|
|
19198
|
+
ipv6Prefix: "2001:4860:4801:17::/64"
|
|
19199
|
+
},
|
|
19200
|
+
{
|
|
19201
|
+
ipv6Prefix: "2001:4860:4801:18::/64"
|
|
19202
|
+
},
|
|
19203
|
+
{
|
|
19204
|
+
ipv6Prefix: "2001:4860:4801:19::/64"
|
|
19205
|
+
},
|
|
19206
|
+
{
|
|
19207
|
+
ipv6Prefix: "2001:4860:4801:1a::/64"
|
|
19208
|
+
},
|
|
19209
|
+
{
|
|
19210
|
+
ipv6Prefix: "2001:4860:4801:1b::/64"
|
|
19211
|
+
},
|
|
19212
|
+
{
|
|
19213
|
+
ipv6Prefix: "2001:4860:4801:1c::/64"
|
|
19214
|
+
},
|
|
19215
|
+
{
|
|
19216
|
+
ipv6Prefix: "2001:4860:4801:1d::/64"
|
|
19217
|
+
},
|
|
19218
|
+
{
|
|
19219
|
+
ipv6Prefix: "2001:4860:4801:1e::/64"
|
|
19220
|
+
},
|
|
19221
|
+
{
|
|
19222
|
+
ipv6Prefix: "2001:4860:4801:1f::/64"
|
|
19223
|
+
},
|
|
19224
|
+
{
|
|
19225
|
+
ipv6Prefix: "2001:4860:4801:20::/64"
|
|
19226
|
+
},
|
|
19227
|
+
{
|
|
19228
|
+
ipv6Prefix: "2001:4860:4801:21::/64"
|
|
19229
|
+
},
|
|
19230
|
+
{
|
|
19231
|
+
ipv6Prefix: "2001:4860:4801:22::/64"
|
|
19232
|
+
},
|
|
19233
|
+
{
|
|
19234
|
+
ipv6Prefix: "2001:4860:4801:23::/64"
|
|
19235
|
+
},
|
|
19236
|
+
{
|
|
19237
|
+
ipv6Prefix: "2001:4860:4801:24::/64"
|
|
19238
|
+
},
|
|
19239
|
+
{
|
|
19240
|
+
ipv6Prefix: "2001:4860:4801:25::/64"
|
|
19241
|
+
},
|
|
19242
|
+
{
|
|
19243
|
+
ipv6Prefix: "2001:4860:4801:26::/64"
|
|
19244
|
+
},
|
|
19245
|
+
{
|
|
19246
|
+
ipv6Prefix: "2001:4860:4801:27::/64"
|
|
19247
|
+
},
|
|
19248
|
+
{
|
|
19249
|
+
ipv6Prefix: "2001:4860:4801:28::/64"
|
|
19250
|
+
},
|
|
19251
|
+
{
|
|
19252
|
+
ipv6Prefix: "2001:4860:4801:29::/64"
|
|
19253
|
+
},
|
|
19254
|
+
{
|
|
19255
|
+
ipv6Prefix: "2001:4860:4801:2::/64"
|
|
19256
|
+
},
|
|
19257
|
+
{
|
|
19258
|
+
ipv6Prefix: "2001:4860:4801:2a::/64"
|
|
19259
|
+
},
|
|
19260
|
+
{
|
|
19261
|
+
ipv6Prefix: "2001:4860:4801:2b::/64"
|
|
19262
|
+
},
|
|
19263
|
+
{
|
|
19264
|
+
ipv6Prefix: "2001:4860:4801:2c::/64"
|
|
19265
|
+
},
|
|
19266
|
+
{
|
|
19267
|
+
ipv6Prefix: "2001:4860:4801:2d::/64"
|
|
19268
|
+
},
|
|
19269
|
+
{
|
|
19270
|
+
ipv6Prefix: "2001:4860:4801:2e::/64"
|
|
19271
|
+
},
|
|
19272
|
+
{
|
|
19273
|
+
ipv6Prefix: "2001:4860:4801:2f::/64"
|
|
19274
|
+
},
|
|
19275
|
+
{
|
|
19276
|
+
ipv6Prefix: "2001:4860:4801:30::/64"
|
|
19277
|
+
},
|
|
19278
|
+
{
|
|
19279
|
+
ipv6Prefix: "2001:4860:4801:31::/64"
|
|
19280
|
+
},
|
|
19281
|
+
{
|
|
19282
|
+
ipv6Prefix: "2001:4860:4801:32::/64"
|
|
19283
|
+
},
|
|
19284
|
+
{
|
|
19285
|
+
ipv6Prefix: "2001:4860:4801:33::/64"
|
|
19286
|
+
},
|
|
19287
|
+
{
|
|
19288
|
+
ipv6Prefix: "2001:4860:4801:34::/64"
|
|
19289
|
+
},
|
|
19290
|
+
{
|
|
19291
|
+
ipv6Prefix: "2001:4860:4801:35::/64"
|
|
19292
|
+
},
|
|
19293
|
+
{
|
|
19294
|
+
ipv6Prefix: "2001:4860:4801:36::/64"
|
|
19295
|
+
},
|
|
19296
|
+
{
|
|
19297
|
+
ipv6Prefix: "2001:4860:4801:37::/64"
|
|
19298
|
+
},
|
|
19299
|
+
{
|
|
19300
|
+
ipv6Prefix: "2001:4860:4801:38::/64"
|
|
19301
|
+
},
|
|
19302
|
+
{
|
|
19303
|
+
ipv6Prefix: "2001:4860:4801:39::/64"
|
|
19304
|
+
},
|
|
19305
|
+
{
|
|
19306
|
+
ipv6Prefix: "2001:4860:4801:3a::/64"
|
|
19307
|
+
},
|
|
19308
|
+
{
|
|
19309
|
+
ipv6Prefix: "2001:4860:4801:3b::/64"
|
|
19310
|
+
},
|
|
19311
|
+
{
|
|
19312
|
+
ipv6Prefix: "2001:4860:4801:3c::/64"
|
|
19313
|
+
},
|
|
19314
|
+
{
|
|
19315
|
+
ipv6Prefix: "2001:4860:4801:3d::/64"
|
|
19316
|
+
},
|
|
19317
|
+
{
|
|
19318
|
+
ipv6Prefix: "2001:4860:4801:3e::/64"
|
|
19319
|
+
},
|
|
19320
|
+
{
|
|
19321
|
+
ipv6Prefix: "2001:4860:4801:3f::/64"
|
|
19322
|
+
},
|
|
19323
|
+
{
|
|
19324
|
+
ipv6Prefix: "2001:4860:4801:40::/64"
|
|
19325
|
+
},
|
|
19326
|
+
{
|
|
19327
|
+
ipv6Prefix: "2001:4860:4801:41::/64"
|
|
19328
|
+
},
|
|
19329
|
+
{
|
|
19330
|
+
ipv6Prefix: "2001:4860:4801:42::/64"
|
|
19331
|
+
},
|
|
19332
|
+
{
|
|
19333
|
+
ipv6Prefix: "2001:4860:4801:44::/64"
|
|
19334
|
+
},
|
|
19335
|
+
{
|
|
19336
|
+
ipv6Prefix: "2001:4860:4801:45::/64"
|
|
19337
|
+
},
|
|
19338
|
+
{
|
|
19339
|
+
ipv6Prefix: "2001:4860:4801:46::/64"
|
|
19340
|
+
},
|
|
19341
|
+
{
|
|
19342
|
+
ipv6Prefix: "2001:4860:4801:47::/64"
|
|
19343
|
+
},
|
|
19344
|
+
{
|
|
19345
|
+
ipv6Prefix: "2001:4860:4801:48::/64"
|
|
19346
|
+
},
|
|
19347
|
+
{
|
|
19348
|
+
ipv6Prefix: "2001:4860:4801:49::/64"
|
|
19349
|
+
},
|
|
19350
|
+
{
|
|
19351
|
+
ipv6Prefix: "2001:4860:4801:4a::/64"
|
|
19352
|
+
},
|
|
19353
|
+
{
|
|
19354
|
+
ipv6Prefix: "2001:4860:4801:4b::/64"
|
|
19355
|
+
},
|
|
19356
|
+
{
|
|
19357
|
+
ipv6Prefix: "2001:4860:4801:4c::/64"
|
|
19358
|
+
},
|
|
19359
|
+
{
|
|
19360
|
+
ipv6Prefix: "2001:4860:4801:4d::/64"
|
|
19361
|
+
},
|
|
19362
|
+
{
|
|
19363
|
+
ipv6Prefix: "2001:4860:4801:4e::/64"
|
|
19364
|
+
},
|
|
19365
|
+
{
|
|
19366
|
+
ipv6Prefix: "2001:4860:4801:50::/64"
|
|
19367
|
+
},
|
|
19368
|
+
{
|
|
19369
|
+
ipv6Prefix: "2001:4860:4801:51::/64"
|
|
19370
|
+
},
|
|
19371
|
+
{
|
|
19372
|
+
ipv6Prefix: "2001:4860:4801:52::/64"
|
|
19373
|
+
},
|
|
19374
|
+
{
|
|
19375
|
+
ipv6Prefix: "2001:4860:4801:53::/64"
|
|
19376
|
+
},
|
|
19377
|
+
{
|
|
19378
|
+
ipv6Prefix: "2001:4860:4801:54::/64"
|
|
19379
|
+
},
|
|
19380
|
+
{
|
|
19381
|
+
ipv6Prefix: "2001:4860:4801:55::/64"
|
|
19382
|
+
},
|
|
19383
|
+
{
|
|
19384
|
+
ipv6Prefix: "2001:4860:4801:56::/64"
|
|
19385
|
+
},
|
|
19386
|
+
{
|
|
19387
|
+
ipv6Prefix: "2001:4860:4801:57::/64"
|
|
19388
|
+
},
|
|
19389
|
+
{
|
|
19390
|
+
ipv6Prefix: "2001:4860:4801:58::/64"
|
|
19391
|
+
},
|
|
19392
|
+
{
|
|
19393
|
+
ipv6Prefix: "2001:4860:4801:59::/64"
|
|
19394
|
+
},
|
|
19395
|
+
{
|
|
19396
|
+
ipv6Prefix: "2001:4860:4801:60::/64"
|
|
19397
|
+
},
|
|
19398
|
+
{
|
|
19399
|
+
ipv6Prefix: "2001:4860:4801:61::/64"
|
|
19400
|
+
},
|
|
19401
|
+
{
|
|
19402
|
+
ipv6Prefix: "2001:4860:4801:62::/64"
|
|
19403
|
+
},
|
|
19404
|
+
{
|
|
19405
|
+
ipv6Prefix: "2001:4860:4801:63::/64"
|
|
19406
|
+
},
|
|
19407
|
+
{
|
|
19408
|
+
ipv6Prefix: "2001:4860:4801:64::/64"
|
|
19409
|
+
},
|
|
19410
|
+
{
|
|
19411
|
+
ipv6Prefix: "2001:4860:4801:65::/64"
|
|
19412
|
+
},
|
|
19413
|
+
{
|
|
19414
|
+
ipv6Prefix: "2001:4860:4801:66::/64"
|
|
19415
|
+
},
|
|
19416
|
+
{
|
|
19417
|
+
ipv6Prefix: "2001:4860:4801:67::/64"
|
|
19418
|
+
},
|
|
19419
|
+
{
|
|
19420
|
+
ipv6Prefix: "2001:4860:4801:68::/64"
|
|
19421
|
+
},
|
|
19422
|
+
{
|
|
19423
|
+
ipv6Prefix: "2001:4860:4801:69::/64"
|
|
19424
|
+
},
|
|
19425
|
+
{
|
|
19426
|
+
ipv6Prefix: "2001:4860:4801:6a::/64"
|
|
19427
|
+
},
|
|
19428
|
+
{
|
|
19429
|
+
ipv6Prefix: "2001:4860:4801:6b::/64"
|
|
19430
|
+
},
|
|
19431
|
+
{
|
|
19432
|
+
ipv6Prefix: "2001:4860:4801:6c::/64"
|
|
19433
|
+
},
|
|
19434
|
+
{
|
|
19435
|
+
ipv6Prefix: "2001:4860:4801:6d::/64"
|
|
19436
|
+
},
|
|
19437
|
+
{
|
|
19438
|
+
ipv6Prefix: "2001:4860:4801:6e::/64"
|
|
19439
|
+
},
|
|
19440
|
+
{
|
|
19441
|
+
ipv6Prefix: "2001:4860:4801:6f::/64"
|
|
19442
|
+
},
|
|
19443
|
+
{
|
|
19444
|
+
ipv6Prefix: "2001:4860:4801:70::/64"
|
|
19445
|
+
},
|
|
19446
|
+
{
|
|
19447
|
+
ipv6Prefix: "2001:4860:4801:71::/64"
|
|
19448
|
+
},
|
|
19449
|
+
{
|
|
19450
|
+
ipv6Prefix: "2001:4860:4801:72::/64"
|
|
19451
|
+
},
|
|
19452
|
+
{
|
|
19453
|
+
ipv6Prefix: "2001:4860:4801:73::/64"
|
|
19454
|
+
},
|
|
19455
|
+
{
|
|
19456
|
+
ipv6Prefix: "2001:4860:4801:74::/64"
|
|
19457
|
+
},
|
|
19458
|
+
{
|
|
19459
|
+
ipv6Prefix: "2001:4860:4801:75::/64"
|
|
19460
|
+
},
|
|
19461
|
+
{
|
|
19462
|
+
ipv6Prefix: "2001:4860:4801:76::/64"
|
|
19463
|
+
},
|
|
19464
|
+
{
|
|
19465
|
+
ipv6Prefix: "2001:4860:4801:77::/64"
|
|
19466
|
+
},
|
|
19467
|
+
{
|
|
19468
|
+
ipv6Prefix: "2001:4860:4801:78::/64"
|
|
19469
|
+
},
|
|
19470
|
+
{
|
|
19471
|
+
ipv6Prefix: "2001:4860:4801:79::/64"
|
|
19472
|
+
},
|
|
19473
|
+
{
|
|
19474
|
+
ipv6Prefix: "2001:4860:4801:7a::/64"
|
|
19475
|
+
},
|
|
19476
|
+
{
|
|
19477
|
+
ipv6Prefix: "2001:4860:4801:7b::/64"
|
|
19478
|
+
},
|
|
19479
|
+
{
|
|
19480
|
+
ipv6Prefix: "2001:4860:4801:7c::/64"
|
|
19481
|
+
},
|
|
19482
|
+
{
|
|
19483
|
+
ipv6Prefix: "2001:4860:4801:7d::/64"
|
|
19484
|
+
},
|
|
19485
|
+
{
|
|
19486
|
+
ipv6Prefix: "2001:4860:4801:80::/64"
|
|
19487
|
+
},
|
|
19488
|
+
{
|
|
19489
|
+
ipv6Prefix: "2001:4860:4801:81::/64"
|
|
19490
|
+
},
|
|
19491
|
+
{
|
|
19492
|
+
ipv6Prefix: "2001:4860:4801:82::/64"
|
|
19493
|
+
},
|
|
19494
|
+
{
|
|
19495
|
+
ipv6Prefix: "2001:4860:4801:83::/64"
|
|
19496
|
+
},
|
|
19497
|
+
{
|
|
19498
|
+
ipv6Prefix: "2001:4860:4801:84::/64"
|
|
19499
|
+
},
|
|
19500
|
+
{
|
|
19501
|
+
ipv6Prefix: "2001:4860:4801:85::/64"
|
|
19502
|
+
},
|
|
19503
|
+
{
|
|
19504
|
+
ipv6Prefix: "2001:4860:4801:86::/64"
|
|
19505
|
+
},
|
|
19506
|
+
{
|
|
19507
|
+
ipv6Prefix: "2001:4860:4801:87::/64"
|
|
19508
|
+
},
|
|
19509
|
+
{
|
|
19510
|
+
ipv6Prefix: "2001:4860:4801:88::/64"
|
|
19511
|
+
},
|
|
19512
|
+
{
|
|
19513
|
+
ipv6Prefix: "2001:4860:4801:90::/64"
|
|
19514
|
+
},
|
|
19515
|
+
{
|
|
19516
|
+
ipv6Prefix: "2001:4860:4801:91::/64"
|
|
19517
|
+
},
|
|
19518
|
+
{
|
|
19519
|
+
ipv6Prefix: "2001:4860:4801:92::/64"
|
|
19520
|
+
},
|
|
19521
|
+
{
|
|
19522
|
+
ipv6Prefix: "2001:4860:4801:93::/64"
|
|
19523
|
+
},
|
|
19524
|
+
{
|
|
19525
|
+
ipv6Prefix: "2001:4860:4801:94::/64"
|
|
19526
|
+
},
|
|
19527
|
+
{
|
|
19528
|
+
ipv6Prefix: "2001:4860:4801:95::/64"
|
|
19529
|
+
},
|
|
19530
|
+
{
|
|
19531
|
+
ipv6Prefix: "2001:4860:4801:96::/64"
|
|
19532
|
+
},
|
|
19533
|
+
{
|
|
19534
|
+
ipv6Prefix: "2001:4860:4801:97::/64"
|
|
19535
|
+
},
|
|
19536
|
+
{
|
|
19537
|
+
ipv6Prefix: "2001:4860:4801:a0::/64"
|
|
19538
|
+
},
|
|
19539
|
+
{
|
|
19540
|
+
ipv6Prefix: "2001:4860:4801:a1::/64"
|
|
19541
|
+
},
|
|
19542
|
+
{
|
|
19543
|
+
ipv6Prefix: "2001:4860:4801:a2::/64"
|
|
19544
|
+
},
|
|
19545
|
+
{
|
|
19546
|
+
ipv6Prefix: "2001:4860:4801:a3::/64"
|
|
19547
|
+
},
|
|
19548
|
+
{
|
|
19549
|
+
ipv6Prefix: "2001:4860:4801:a4::/64"
|
|
19550
|
+
},
|
|
19551
|
+
{
|
|
19552
|
+
ipv6Prefix: "2001:4860:4801:a5::/64"
|
|
19553
|
+
},
|
|
19554
|
+
{
|
|
19555
|
+
ipv6Prefix: "2001:4860:4801:a6::/64"
|
|
19556
|
+
},
|
|
19557
|
+
{
|
|
19558
|
+
ipv6Prefix: "2001:4860:4801:a7::/64"
|
|
19559
|
+
},
|
|
19560
|
+
{
|
|
19561
|
+
ipv6Prefix: "2001:4860:4801:a8::/64"
|
|
19562
|
+
},
|
|
19563
|
+
{
|
|
19564
|
+
ipv6Prefix: "2001:4860:4801:a9::/64"
|
|
19565
|
+
},
|
|
19566
|
+
{
|
|
19567
|
+
ipv6Prefix: "2001:4860:4801:aa::/64"
|
|
19568
|
+
},
|
|
19569
|
+
{
|
|
19570
|
+
ipv6Prefix: "2001:4860:4801:ab::/64"
|
|
19571
|
+
},
|
|
19572
|
+
{
|
|
19573
|
+
ipv6Prefix: "2001:4860:4801:ac::/64"
|
|
19574
|
+
},
|
|
19575
|
+
{
|
|
19576
|
+
ipv6Prefix: "2001:4860:4801:ad::/64"
|
|
19577
|
+
},
|
|
19578
|
+
{
|
|
19579
|
+
ipv6Prefix: "2001:4860:4801:ae::/64"
|
|
19580
|
+
},
|
|
19581
|
+
{
|
|
19582
|
+
ipv6Prefix: "2001:4860:4801:b0::/64"
|
|
19583
|
+
},
|
|
19584
|
+
{
|
|
19585
|
+
ipv6Prefix: "2001:4860:4801:b1::/64"
|
|
19586
|
+
},
|
|
19587
|
+
{
|
|
19588
|
+
ipv6Prefix: "2001:4860:4801:b2::/64"
|
|
19589
|
+
},
|
|
19590
|
+
{
|
|
19591
|
+
ipv6Prefix: "2001:4860:4801:b3::/64"
|
|
19592
|
+
},
|
|
19593
|
+
{
|
|
19594
|
+
ipv6Prefix: "2001:4860:4801:b4::/64"
|
|
19595
|
+
},
|
|
19596
|
+
{
|
|
19597
|
+
ipv6Prefix: "2001:4860:4801:b5::/64"
|
|
19598
|
+
},
|
|
19599
|
+
{
|
|
19600
|
+
ipv6Prefix: "2001:4860:4801:b6::/64"
|
|
19601
|
+
},
|
|
19602
|
+
{
|
|
19603
|
+
ipv6Prefix: "2001:4860:4801:c::/64"
|
|
19604
|
+
},
|
|
19605
|
+
{
|
|
19606
|
+
ipv6Prefix: "2001:4860:4801:f::/64"
|
|
19607
|
+
},
|
|
19608
|
+
{
|
|
19609
|
+
ipv4Prefix: "192.178.4.0/27"
|
|
19610
|
+
},
|
|
19611
|
+
{
|
|
19612
|
+
ipv4Prefix: "192.178.4.128/27"
|
|
19613
|
+
},
|
|
19614
|
+
{
|
|
19615
|
+
ipv4Prefix: "192.178.4.160/27"
|
|
19616
|
+
},
|
|
19617
|
+
{
|
|
19618
|
+
ipv4Prefix: "192.178.4.192/27"
|
|
19619
|
+
},
|
|
19620
|
+
{
|
|
19621
|
+
ipv4Prefix: "192.178.4.224/27"
|
|
19622
|
+
},
|
|
19623
|
+
{
|
|
19624
|
+
ipv4Prefix: "192.178.4.32/27"
|
|
19625
|
+
},
|
|
19626
|
+
{
|
|
19627
|
+
ipv4Prefix: "192.178.4.64/27"
|
|
19628
|
+
},
|
|
19629
|
+
{
|
|
19630
|
+
ipv4Prefix: "192.178.4.96/27"
|
|
19631
|
+
},
|
|
19632
|
+
{
|
|
19633
|
+
ipv4Prefix: "192.178.5.0/27"
|
|
19634
|
+
},
|
|
19635
|
+
{
|
|
19636
|
+
ipv4Prefix: "192.178.6.0/27"
|
|
19637
|
+
},
|
|
19638
|
+
{
|
|
19639
|
+
ipv4Prefix: "192.178.6.128/27"
|
|
19640
|
+
},
|
|
19641
|
+
{
|
|
19642
|
+
ipv4Prefix: "192.178.6.160/27"
|
|
19643
|
+
},
|
|
19644
|
+
{
|
|
19645
|
+
ipv4Prefix: "192.178.6.192/27"
|
|
19646
|
+
},
|
|
19647
|
+
{
|
|
19648
|
+
ipv4Prefix: "192.178.6.224/27"
|
|
19649
|
+
},
|
|
19650
|
+
{
|
|
19651
|
+
ipv4Prefix: "192.178.6.32/27"
|
|
19652
|
+
},
|
|
19653
|
+
{
|
|
19654
|
+
ipv4Prefix: "192.178.6.64/27"
|
|
19655
|
+
},
|
|
19656
|
+
{
|
|
19657
|
+
ipv4Prefix: "192.178.6.96/27"
|
|
19658
|
+
},
|
|
19659
|
+
{
|
|
19660
|
+
ipv4Prefix: "192.178.7.0/27"
|
|
19661
|
+
},
|
|
19662
|
+
{
|
|
19663
|
+
ipv4Prefix: "192.178.7.128/27"
|
|
19664
|
+
},
|
|
19665
|
+
{
|
|
19666
|
+
ipv4Prefix: "192.178.7.160/27"
|
|
19667
|
+
},
|
|
19668
|
+
{
|
|
19669
|
+
ipv4Prefix: "192.178.7.192/27"
|
|
19670
|
+
},
|
|
19671
|
+
{
|
|
19672
|
+
ipv4Prefix: "192.178.7.224/27"
|
|
19673
|
+
},
|
|
19674
|
+
{
|
|
19675
|
+
ipv4Prefix: "192.178.7.32/27"
|
|
19676
|
+
},
|
|
19677
|
+
{
|
|
19678
|
+
ipv4Prefix: "192.178.7.64/27"
|
|
19679
|
+
},
|
|
19680
|
+
{
|
|
19681
|
+
ipv4Prefix: "192.178.7.96/27"
|
|
19682
|
+
},
|
|
19683
|
+
{
|
|
19684
|
+
ipv4Prefix: "34.100.182.96/28"
|
|
19685
|
+
},
|
|
19686
|
+
{
|
|
19687
|
+
ipv4Prefix: "34.101.50.144/28"
|
|
19688
|
+
},
|
|
19689
|
+
{
|
|
19690
|
+
ipv4Prefix: "34.118.254.0/28"
|
|
19691
|
+
},
|
|
19692
|
+
{
|
|
19693
|
+
ipv4Prefix: "34.118.66.0/28"
|
|
19694
|
+
},
|
|
19695
|
+
{
|
|
19696
|
+
ipv4Prefix: "34.126.178.96/28"
|
|
19697
|
+
},
|
|
19698
|
+
{
|
|
19699
|
+
ipv4Prefix: "34.146.150.144/28"
|
|
19700
|
+
},
|
|
19701
|
+
{
|
|
19702
|
+
ipv4Prefix: "34.147.110.144/28"
|
|
19703
|
+
},
|
|
19704
|
+
{
|
|
19705
|
+
ipv4Prefix: "34.151.74.144/28"
|
|
19706
|
+
},
|
|
19707
|
+
{
|
|
19708
|
+
ipv4Prefix: "34.152.50.64/28"
|
|
19709
|
+
},
|
|
19710
|
+
{
|
|
19711
|
+
ipv4Prefix: "34.154.114.144/28"
|
|
19712
|
+
},
|
|
19713
|
+
{
|
|
19714
|
+
ipv4Prefix: "34.155.98.32/28"
|
|
19715
|
+
},
|
|
19716
|
+
{
|
|
19717
|
+
ipv4Prefix: "34.165.18.176/28"
|
|
19718
|
+
},
|
|
19719
|
+
{
|
|
19720
|
+
ipv4Prefix: "34.175.160.64/28"
|
|
19721
|
+
},
|
|
19722
|
+
{
|
|
19723
|
+
ipv4Prefix: "34.176.130.16/28"
|
|
19724
|
+
},
|
|
19725
|
+
{
|
|
19726
|
+
ipv4Prefix: "34.22.85.0/27"
|
|
19727
|
+
},
|
|
19728
|
+
{
|
|
19729
|
+
ipv4Prefix: "34.64.82.64/28"
|
|
19730
|
+
},
|
|
19731
|
+
{
|
|
19732
|
+
ipv4Prefix: "34.65.242.112/28"
|
|
19733
|
+
},
|
|
19734
|
+
{
|
|
19735
|
+
ipv4Prefix: "34.80.50.80/28"
|
|
19736
|
+
},
|
|
19737
|
+
{
|
|
19738
|
+
ipv4Prefix: "34.88.194.0/28"
|
|
19739
|
+
},
|
|
19740
|
+
{
|
|
19741
|
+
ipv4Prefix: "34.89.10.80/28"
|
|
19742
|
+
},
|
|
19743
|
+
{
|
|
19744
|
+
ipv4Prefix: "34.89.198.80/28"
|
|
19745
|
+
},
|
|
19746
|
+
{
|
|
19747
|
+
ipv4Prefix: "34.96.162.48/28"
|
|
19748
|
+
},
|
|
19749
|
+
{
|
|
19750
|
+
ipv4Prefix: "35.247.243.240/28"
|
|
19751
|
+
},
|
|
19752
|
+
{
|
|
19753
|
+
ipv4Prefix: "66.249.64.0/27"
|
|
19754
|
+
},
|
|
19755
|
+
{
|
|
19756
|
+
ipv4Prefix: "66.249.64.128/27"
|
|
19757
|
+
},
|
|
19758
|
+
{
|
|
19759
|
+
ipv4Prefix: "66.249.64.160/27"
|
|
19760
|
+
},
|
|
19761
|
+
{
|
|
19762
|
+
ipv4Prefix: "66.249.64.192/27"
|
|
19763
|
+
},
|
|
19764
|
+
{
|
|
19765
|
+
ipv4Prefix: "66.249.64.224/27"
|
|
19766
|
+
},
|
|
19767
|
+
{
|
|
19768
|
+
ipv4Prefix: "66.249.64.32/27"
|
|
19769
|
+
},
|
|
19770
|
+
{
|
|
19771
|
+
ipv4Prefix: "66.249.64.64/27"
|
|
19772
|
+
},
|
|
19773
|
+
{
|
|
19774
|
+
ipv4Prefix: "66.249.64.96/27"
|
|
19775
|
+
},
|
|
19776
|
+
{
|
|
19777
|
+
ipv4Prefix: "66.249.65.0/27"
|
|
19778
|
+
},
|
|
19779
|
+
{
|
|
19780
|
+
ipv4Prefix: "66.249.65.128/27"
|
|
19781
|
+
},
|
|
19782
|
+
{
|
|
19783
|
+
ipv4Prefix: "66.249.65.160/27"
|
|
19784
|
+
},
|
|
19785
|
+
{
|
|
19786
|
+
ipv4Prefix: "66.249.65.192/27"
|
|
19787
|
+
},
|
|
19788
|
+
{
|
|
19789
|
+
ipv4Prefix: "66.249.65.224/27"
|
|
19790
|
+
},
|
|
19791
|
+
{
|
|
19792
|
+
ipv4Prefix: "66.249.65.32/27"
|
|
19793
|
+
},
|
|
19794
|
+
{
|
|
19795
|
+
ipv4Prefix: "66.249.65.64/27"
|
|
19796
|
+
},
|
|
19797
|
+
{
|
|
19798
|
+
ipv4Prefix: "66.249.65.96/27"
|
|
19799
|
+
},
|
|
19800
|
+
{
|
|
19801
|
+
ipv4Prefix: "66.249.66.0/27"
|
|
19802
|
+
},
|
|
19803
|
+
{
|
|
19804
|
+
ipv4Prefix: "66.249.66.128/27"
|
|
19805
|
+
},
|
|
19806
|
+
{
|
|
19807
|
+
ipv4Prefix: "66.249.66.160/27"
|
|
19808
|
+
},
|
|
19809
|
+
{
|
|
19810
|
+
ipv4Prefix: "66.249.66.192/27"
|
|
19811
|
+
},
|
|
19812
|
+
{
|
|
19813
|
+
ipv4Prefix: "66.249.66.224/27"
|
|
19814
|
+
},
|
|
19815
|
+
{
|
|
19816
|
+
ipv4Prefix: "66.249.66.32/27"
|
|
19817
|
+
},
|
|
19818
|
+
{
|
|
19819
|
+
ipv4Prefix: "66.249.66.64/27"
|
|
19820
|
+
},
|
|
19821
|
+
{
|
|
19822
|
+
ipv4Prefix: "66.249.66.96/27"
|
|
19823
|
+
},
|
|
19824
|
+
{
|
|
19825
|
+
ipv4Prefix: "66.249.67.0/27"
|
|
19826
|
+
},
|
|
19827
|
+
{
|
|
19828
|
+
ipv4Prefix: "66.249.67.32/27"
|
|
19829
|
+
},
|
|
19830
|
+
{
|
|
19831
|
+
ipv4Prefix: "66.249.67.64/27"
|
|
19832
|
+
},
|
|
19833
|
+
{
|
|
19834
|
+
ipv4Prefix: "66.249.68.0/27"
|
|
19835
|
+
},
|
|
19836
|
+
{
|
|
19837
|
+
ipv4Prefix: "66.249.68.128/27"
|
|
19838
|
+
},
|
|
19839
|
+
{
|
|
19840
|
+
ipv4Prefix: "66.249.68.160/27"
|
|
19841
|
+
},
|
|
19842
|
+
{
|
|
19843
|
+
ipv4Prefix: "66.249.68.192/27"
|
|
19844
|
+
},
|
|
19845
|
+
{
|
|
19846
|
+
ipv4Prefix: "66.249.68.32/27"
|
|
19847
|
+
},
|
|
19848
|
+
{
|
|
19849
|
+
ipv4Prefix: "66.249.68.64/27"
|
|
19850
|
+
},
|
|
19851
|
+
{
|
|
19852
|
+
ipv4Prefix: "66.249.68.96/27"
|
|
19853
|
+
},
|
|
19854
|
+
{
|
|
19855
|
+
ipv4Prefix: "66.249.69.0/27"
|
|
19856
|
+
},
|
|
19857
|
+
{
|
|
19858
|
+
ipv4Prefix: "66.249.69.128/27"
|
|
19859
|
+
},
|
|
19860
|
+
{
|
|
19861
|
+
ipv4Prefix: "66.249.69.160/27"
|
|
19862
|
+
},
|
|
19863
|
+
{
|
|
19864
|
+
ipv4Prefix: "66.249.69.192/27"
|
|
19865
|
+
},
|
|
19866
|
+
{
|
|
19867
|
+
ipv4Prefix: "66.249.69.224/27"
|
|
19868
|
+
},
|
|
19869
|
+
{
|
|
19870
|
+
ipv4Prefix: "66.249.69.32/27"
|
|
19871
|
+
},
|
|
19872
|
+
{
|
|
19873
|
+
ipv4Prefix: "66.249.69.64/27"
|
|
19874
|
+
},
|
|
19875
|
+
{
|
|
19876
|
+
ipv4Prefix: "66.249.69.96/27"
|
|
19877
|
+
},
|
|
19878
|
+
{
|
|
19879
|
+
ipv4Prefix: "66.249.70.0/27"
|
|
19880
|
+
},
|
|
19881
|
+
{
|
|
19882
|
+
ipv4Prefix: "66.249.70.128/27"
|
|
19883
|
+
},
|
|
19884
|
+
{
|
|
19885
|
+
ipv4Prefix: "66.249.70.160/27"
|
|
19886
|
+
},
|
|
19887
|
+
{
|
|
19888
|
+
ipv4Prefix: "66.249.70.192/27"
|
|
19889
|
+
},
|
|
19890
|
+
{
|
|
19891
|
+
ipv4Prefix: "66.249.70.224/27"
|
|
19892
|
+
},
|
|
19893
|
+
{
|
|
19894
|
+
ipv4Prefix: "66.249.70.32/27"
|
|
19895
|
+
},
|
|
19896
|
+
{
|
|
19897
|
+
ipv4Prefix: "66.249.70.64/27"
|
|
19898
|
+
},
|
|
19899
|
+
{
|
|
19900
|
+
ipv4Prefix: "66.249.70.96/27"
|
|
19901
|
+
},
|
|
19902
|
+
{
|
|
19903
|
+
ipv4Prefix: "66.249.71.0/27"
|
|
19904
|
+
},
|
|
19905
|
+
{
|
|
19906
|
+
ipv4Prefix: "66.249.71.128/27"
|
|
19907
|
+
},
|
|
19908
|
+
{
|
|
19909
|
+
ipv4Prefix: "66.249.71.160/27"
|
|
19910
|
+
},
|
|
19911
|
+
{
|
|
19912
|
+
ipv4Prefix: "66.249.71.192/27"
|
|
19913
|
+
},
|
|
19914
|
+
{
|
|
19915
|
+
ipv4Prefix: "66.249.71.224/27"
|
|
19916
|
+
},
|
|
19917
|
+
{
|
|
19918
|
+
ipv4Prefix: "66.249.71.32/27"
|
|
19919
|
+
},
|
|
19920
|
+
{
|
|
19921
|
+
ipv4Prefix: "66.249.71.64/27"
|
|
19922
|
+
},
|
|
19923
|
+
{
|
|
19924
|
+
ipv4Prefix: "66.249.71.96/27"
|
|
19925
|
+
},
|
|
19926
|
+
{
|
|
19927
|
+
ipv4Prefix: "66.249.72.0/27"
|
|
19928
|
+
},
|
|
19929
|
+
{
|
|
19930
|
+
ipv4Prefix: "66.249.72.128/27"
|
|
19931
|
+
},
|
|
19932
|
+
{
|
|
19933
|
+
ipv4Prefix: "66.249.72.160/27"
|
|
19934
|
+
},
|
|
19935
|
+
{
|
|
19936
|
+
ipv4Prefix: "66.249.72.192/27"
|
|
19937
|
+
},
|
|
19938
|
+
{
|
|
19939
|
+
ipv4Prefix: "66.249.72.224/27"
|
|
19940
|
+
},
|
|
19941
|
+
{
|
|
19942
|
+
ipv4Prefix: "66.249.72.32/27"
|
|
19943
|
+
},
|
|
19944
|
+
{
|
|
19945
|
+
ipv4Prefix: "66.249.72.64/27"
|
|
19946
|
+
},
|
|
19947
|
+
{
|
|
19948
|
+
ipv4Prefix: "66.249.72.96/27"
|
|
19949
|
+
},
|
|
19950
|
+
{
|
|
19951
|
+
ipv4Prefix: "66.249.73.0/27"
|
|
19952
|
+
},
|
|
19953
|
+
{
|
|
19954
|
+
ipv4Prefix: "66.249.73.128/27"
|
|
19955
|
+
},
|
|
19956
|
+
{
|
|
19957
|
+
ipv4Prefix: "66.249.73.160/27"
|
|
19958
|
+
},
|
|
19959
|
+
{
|
|
19960
|
+
ipv4Prefix: "66.249.73.192/27"
|
|
19961
|
+
},
|
|
19962
|
+
{
|
|
19963
|
+
ipv4Prefix: "66.249.73.224/27"
|
|
19964
|
+
},
|
|
19965
|
+
{
|
|
19966
|
+
ipv4Prefix: "66.249.73.32/27"
|
|
19967
|
+
},
|
|
19968
|
+
{
|
|
19969
|
+
ipv4Prefix: "66.249.73.64/27"
|
|
19970
|
+
},
|
|
19971
|
+
{
|
|
19972
|
+
ipv4Prefix: "66.249.73.96/27"
|
|
19973
|
+
},
|
|
19974
|
+
{
|
|
19975
|
+
ipv4Prefix: "66.249.74.0/27"
|
|
19976
|
+
},
|
|
19977
|
+
{
|
|
19978
|
+
ipv4Prefix: "66.249.74.128/27"
|
|
19979
|
+
},
|
|
19980
|
+
{
|
|
19981
|
+
ipv4Prefix: "66.249.74.160/27"
|
|
19982
|
+
},
|
|
19983
|
+
{
|
|
19984
|
+
ipv4Prefix: "66.249.74.192/27"
|
|
19985
|
+
},
|
|
19986
|
+
{
|
|
19987
|
+
ipv4Prefix: "66.249.74.224/27"
|
|
19988
|
+
},
|
|
19989
|
+
{
|
|
19990
|
+
ipv4Prefix: "66.249.74.32/27"
|
|
19991
|
+
},
|
|
19992
|
+
{
|
|
19993
|
+
ipv4Prefix: "66.249.74.64/27"
|
|
19994
|
+
},
|
|
19995
|
+
{
|
|
19996
|
+
ipv4Prefix: "66.249.74.96/27"
|
|
19997
|
+
},
|
|
19998
|
+
{
|
|
19999
|
+
ipv4Prefix: "66.249.75.0/27"
|
|
20000
|
+
},
|
|
20001
|
+
{
|
|
20002
|
+
ipv4Prefix: "66.249.75.128/27"
|
|
20003
|
+
},
|
|
20004
|
+
{
|
|
20005
|
+
ipv4Prefix: "66.249.75.160/27"
|
|
20006
|
+
},
|
|
20007
|
+
{
|
|
20008
|
+
ipv4Prefix: "66.249.75.192/27"
|
|
20009
|
+
},
|
|
20010
|
+
{
|
|
20011
|
+
ipv4Prefix: "66.249.75.224/27"
|
|
20012
|
+
},
|
|
20013
|
+
{
|
|
20014
|
+
ipv4Prefix: "66.249.75.32/27"
|
|
20015
|
+
},
|
|
20016
|
+
{
|
|
20017
|
+
ipv4Prefix: "66.249.75.64/27"
|
|
20018
|
+
},
|
|
20019
|
+
{
|
|
20020
|
+
ipv4Prefix: "66.249.75.96/27"
|
|
20021
|
+
},
|
|
20022
|
+
{
|
|
20023
|
+
ipv4Prefix: "66.249.76.0/27"
|
|
20024
|
+
},
|
|
20025
|
+
{
|
|
20026
|
+
ipv4Prefix: "66.249.76.128/27"
|
|
20027
|
+
},
|
|
20028
|
+
{
|
|
20029
|
+
ipv4Prefix: "66.249.76.160/27"
|
|
20030
|
+
},
|
|
20031
|
+
{
|
|
20032
|
+
ipv4Prefix: "66.249.76.192/27"
|
|
20033
|
+
},
|
|
20034
|
+
{
|
|
20035
|
+
ipv4Prefix: "66.249.76.224/27"
|
|
20036
|
+
},
|
|
20037
|
+
{
|
|
20038
|
+
ipv4Prefix: "66.249.76.32/27"
|
|
20039
|
+
},
|
|
20040
|
+
{
|
|
20041
|
+
ipv4Prefix: "66.249.76.64/27"
|
|
20042
|
+
},
|
|
20043
|
+
{
|
|
20044
|
+
ipv4Prefix: "66.249.76.96/27"
|
|
20045
|
+
},
|
|
20046
|
+
{
|
|
20047
|
+
ipv4Prefix: "66.249.77.0/27"
|
|
20048
|
+
},
|
|
20049
|
+
{
|
|
20050
|
+
ipv4Prefix: "66.249.77.128/27"
|
|
20051
|
+
},
|
|
20052
|
+
{
|
|
20053
|
+
ipv4Prefix: "66.249.77.160/27"
|
|
20054
|
+
},
|
|
20055
|
+
{
|
|
20056
|
+
ipv4Prefix: "66.249.77.192/27"
|
|
20057
|
+
},
|
|
20058
|
+
{
|
|
20059
|
+
ipv4Prefix: "66.249.77.224/27"
|
|
20060
|
+
},
|
|
20061
|
+
{
|
|
20062
|
+
ipv4Prefix: "66.249.77.32/27"
|
|
20063
|
+
},
|
|
20064
|
+
{
|
|
20065
|
+
ipv4Prefix: "66.249.77.64/27"
|
|
20066
|
+
},
|
|
20067
|
+
{
|
|
20068
|
+
ipv4Prefix: "66.249.77.96/27"
|
|
20069
|
+
},
|
|
20070
|
+
{
|
|
20071
|
+
ipv4Prefix: "66.249.78.0/27"
|
|
20072
|
+
},
|
|
20073
|
+
{
|
|
20074
|
+
ipv4Prefix: "66.249.78.128/27"
|
|
20075
|
+
},
|
|
20076
|
+
{
|
|
20077
|
+
ipv4Prefix: "66.249.78.160/27"
|
|
20078
|
+
},
|
|
20079
|
+
{
|
|
20080
|
+
ipv4Prefix: "66.249.78.32/27"
|
|
20081
|
+
},
|
|
20082
|
+
{
|
|
20083
|
+
ipv4Prefix: "66.249.78.64/27"
|
|
20084
|
+
},
|
|
20085
|
+
{
|
|
20086
|
+
ipv4Prefix: "66.249.78.96/27"
|
|
20087
|
+
},
|
|
20088
|
+
{
|
|
20089
|
+
ipv4Prefix: "66.249.79.0/27"
|
|
20090
|
+
},
|
|
20091
|
+
{
|
|
20092
|
+
ipv4Prefix: "66.249.79.128/27"
|
|
20093
|
+
},
|
|
20094
|
+
{
|
|
20095
|
+
ipv4Prefix: "66.249.79.160/27"
|
|
20096
|
+
},
|
|
20097
|
+
{
|
|
20098
|
+
ipv4Prefix: "66.249.79.192/27"
|
|
20099
|
+
},
|
|
20100
|
+
{
|
|
20101
|
+
ipv4Prefix: "66.249.79.224/27"
|
|
20102
|
+
},
|
|
20103
|
+
{
|
|
20104
|
+
ipv4Prefix: "66.249.79.32/27"
|
|
20105
|
+
},
|
|
20106
|
+
{
|
|
20107
|
+
ipv4Prefix: "66.249.79.64/27"
|
|
20108
|
+
}
|
|
20109
|
+
]
|
|
20110
|
+
};
|
|
20111
|
+
|
|
20112
|
+
// ../integration-traffic/src/ip-ranges/gptbot.json
|
|
20113
|
+
var gptbot_default = {
|
|
20114
|
+
_source: "https://openai.com/gptbot.json",
|
|
20115
|
+
creationTime: "2025-10-30T11:00:00.000000",
|
|
20116
|
+
prefixes: [
|
|
20117
|
+
{
|
|
20118
|
+
ipv4Prefix: "132.196.86.0/24"
|
|
20119
|
+
},
|
|
20120
|
+
{
|
|
20121
|
+
ipv4Prefix: "172.182.202.0/25"
|
|
20122
|
+
},
|
|
20123
|
+
{
|
|
20124
|
+
ipv4Prefix: "172.182.204.0/24"
|
|
20125
|
+
},
|
|
20126
|
+
{
|
|
20127
|
+
ipv4Prefix: "172.182.207.0/25"
|
|
20128
|
+
},
|
|
20129
|
+
{
|
|
20130
|
+
ipv4Prefix: "172.182.214.0/24"
|
|
20131
|
+
},
|
|
20132
|
+
{
|
|
20133
|
+
ipv4Prefix: "172.182.215.0/24"
|
|
20134
|
+
},
|
|
20135
|
+
{
|
|
20136
|
+
ipv4Prefix: "20.125.66.80/28"
|
|
20137
|
+
},
|
|
20138
|
+
{
|
|
20139
|
+
ipv4Prefix: "20.171.206.0/24"
|
|
20140
|
+
},
|
|
20141
|
+
{
|
|
20142
|
+
ipv4Prefix: "20.171.207.0/24"
|
|
20143
|
+
},
|
|
20144
|
+
{
|
|
20145
|
+
ipv4Prefix: "4.227.36.0/25"
|
|
20146
|
+
},
|
|
20147
|
+
{
|
|
20148
|
+
ipv4Prefix: "52.230.152.0/24"
|
|
20149
|
+
},
|
|
20150
|
+
{
|
|
20151
|
+
ipv4Prefix: "74.7.175.128/25"
|
|
20152
|
+
},
|
|
20153
|
+
{
|
|
20154
|
+
ipv4Prefix: "74.7.227.0/25"
|
|
20155
|
+
},
|
|
20156
|
+
{
|
|
20157
|
+
ipv4Prefix: "74.7.227.128/25"
|
|
20158
|
+
},
|
|
20159
|
+
{
|
|
20160
|
+
ipv4Prefix: "74.7.228.0/25"
|
|
20161
|
+
},
|
|
20162
|
+
{
|
|
20163
|
+
ipv4Prefix: "74.7.230.0/25"
|
|
20164
|
+
},
|
|
20165
|
+
{
|
|
20166
|
+
ipv4Prefix: "74.7.241.0/25"
|
|
20167
|
+
},
|
|
20168
|
+
{
|
|
20169
|
+
ipv4Prefix: "74.7.241.128/25"
|
|
20170
|
+
},
|
|
20171
|
+
{
|
|
20172
|
+
ipv4Prefix: "74.7.242.0/25"
|
|
20173
|
+
},
|
|
20174
|
+
{
|
|
20175
|
+
ipv4Prefix: "74.7.243.128/25"
|
|
20176
|
+
},
|
|
20177
|
+
{
|
|
20178
|
+
ipv4Prefix: "74.7.244.0/25"
|
|
20179
|
+
}
|
|
20180
|
+
]
|
|
20181
|
+
};
|
|
20182
|
+
|
|
20183
|
+
// ../integration-traffic/src/ip-ranges/oai-searchbot.json
|
|
20184
|
+
var oai_searchbot_default = {
|
|
20185
|
+
_source: "https://openai.com/searchbot.json",
|
|
20186
|
+
creationTime: "2026-01-02T11:00:00.000000",
|
|
20187
|
+
prefixes: [
|
|
20188
|
+
{
|
|
20189
|
+
ipv4Prefix: "104.210.140.128/28"
|
|
20190
|
+
},
|
|
20191
|
+
{
|
|
20192
|
+
ipv4Prefix: "135.234.64.0/24"
|
|
20193
|
+
},
|
|
20194
|
+
{
|
|
20195
|
+
ipv4Prefix: "172.182.193.224/28"
|
|
20196
|
+
},
|
|
20197
|
+
{
|
|
20198
|
+
ipv4Prefix: "172.182.193.80/28"
|
|
20199
|
+
},
|
|
20200
|
+
{
|
|
20201
|
+
ipv4Prefix: "172.182.194.144/28"
|
|
20202
|
+
},
|
|
20203
|
+
{
|
|
20204
|
+
ipv4Prefix: "172.182.194.32/28"
|
|
20205
|
+
},
|
|
20206
|
+
{
|
|
20207
|
+
ipv4Prefix: "172.182.195.48/28"
|
|
20208
|
+
},
|
|
20209
|
+
{
|
|
20210
|
+
ipv4Prefix: "172.182.209.208/28"
|
|
20211
|
+
},
|
|
20212
|
+
{
|
|
20213
|
+
ipv4Prefix: "172.182.211.192/28"
|
|
20214
|
+
},
|
|
20215
|
+
{
|
|
20216
|
+
ipv4Prefix: "172.182.213.192/28"
|
|
20217
|
+
},
|
|
20218
|
+
{
|
|
20219
|
+
ipv4Prefix: "172.182.224.0/28"
|
|
20220
|
+
},
|
|
20221
|
+
{
|
|
20222
|
+
ipv4Prefix: "172.203.190.128/28"
|
|
20223
|
+
},
|
|
20224
|
+
{
|
|
20225
|
+
ipv4Prefix: "20.14.99.96/28"
|
|
20226
|
+
},
|
|
20227
|
+
{
|
|
20228
|
+
ipv4Prefix: "20.168.18.32/28"
|
|
20229
|
+
},
|
|
20230
|
+
{
|
|
20231
|
+
ipv4Prefix: "20.169.6.224/28"
|
|
20232
|
+
},
|
|
20233
|
+
{
|
|
20234
|
+
ipv4Prefix: "20.169.7.48/28"
|
|
20235
|
+
},
|
|
20236
|
+
{
|
|
20237
|
+
ipv4Prefix: "20.169.77.0/25"
|
|
20238
|
+
},
|
|
20239
|
+
{
|
|
20240
|
+
ipv4Prefix: "20.171.123.64/28"
|
|
20241
|
+
},
|
|
20242
|
+
{
|
|
20243
|
+
ipv4Prefix: "20.171.53.224/28"
|
|
20244
|
+
},
|
|
20245
|
+
{
|
|
20246
|
+
ipv4Prefix: "20.25.151.224/28"
|
|
20247
|
+
},
|
|
20248
|
+
{
|
|
20249
|
+
ipv4Prefix: "20.42.10.176/28"
|
|
20250
|
+
},
|
|
20251
|
+
{
|
|
20252
|
+
ipv4Prefix: "4.227.36.0/25"
|
|
20253
|
+
},
|
|
20254
|
+
{
|
|
20255
|
+
ipv4Prefix: "40.67.175.0/25"
|
|
20256
|
+
},
|
|
20257
|
+
{
|
|
20258
|
+
ipv4Prefix: "40.90.214.16/28"
|
|
20259
|
+
},
|
|
20260
|
+
{
|
|
20261
|
+
ipv4Prefix: "51.8.102.0/24"
|
|
20262
|
+
},
|
|
20263
|
+
{
|
|
20264
|
+
ipv4Prefix: "74.7.175.128/25"
|
|
20265
|
+
},
|
|
20266
|
+
{
|
|
20267
|
+
ipv4Prefix: "74.7.228.0/25"
|
|
20268
|
+
},
|
|
20269
|
+
{
|
|
20270
|
+
ipv4Prefix: "74.7.228.128/25"
|
|
20271
|
+
},
|
|
20272
|
+
{
|
|
20273
|
+
ipv4Prefix: "74.7.229.0/25"
|
|
20274
|
+
},
|
|
20275
|
+
{
|
|
20276
|
+
ipv4Prefix: "74.7.229.128/25"
|
|
20277
|
+
},
|
|
20278
|
+
{
|
|
20279
|
+
ipv4Prefix: "74.7.230.0/25"
|
|
20280
|
+
},
|
|
20281
|
+
{
|
|
20282
|
+
ipv4Prefix: "74.7.241.128/25"
|
|
20283
|
+
},
|
|
20284
|
+
{
|
|
20285
|
+
ipv4Prefix: "74.7.242.128/25"
|
|
20286
|
+
},
|
|
20287
|
+
{
|
|
20288
|
+
ipv4Prefix: "74.7.243.0/25"
|
|
20289
|
+
},
|
|
20290
|
+
{
|
|
20291
|
+
ipv4Prefix: "74.7.244.0/25"
|
|
20292
|
+
}
|
|
20293
|
+
]
|
|
20294
|
+
};
|
|
20295
|
+
|
|
20296
|
+
// ../integration-traffic/src/ip-ranges/perplexity-user.json
|
|
20297
|
+
var perplexity_user_default = {
|
|
20298
|
+
_source: "https://www.perplexity.ai/perplexity-user.json",
|
|
20299
|
+
creationTime: "2025-10-17T10:17:00.000000",
|
|
20300
|
+
prefixes: [
|
|
20301
|
+
{
|
|
20302
|
+
ipv4Prefix: "44.208.221.197/32"
|
|
20303
|
+
},
|
|
20304
|
+
{
|
|
20305
|
+
ipv4Prefix: "34.193.163.52/32"
|
|
20306
|
+
},
|
|
20307
|
+
{
|
|
20308
|
+
ipv4Prefix: "18.97.21.0/30"
|
|
20309
|
+
},
|
|
20310
|
+
{
|
|
20311
|
+
ipv4Prefix: "18.97.43.80/29"
|
|
20312
|
+
}
|
|
20313
|
+
]
|
|
20314
|
+
};
|
|
20315
|
+
|
|
20316
|
+
// ../integration-traffic/src/ip-ranges/perplexitybot.json
|
|
20317
|
+
var perplexitybot_default = {
|
|
20318
|
+
_source: "https://www.perplexity.ai/perplexitybot.json",
|
|
20319
|
+
creationTime: "2025-02-07T16:56:00.000000",
|
|
20320
|
+
prefixes: [
|
|
20321
|
+
{
|
|
20322
|
+
ipv4Prefix: "107.20.236.150/32"
|
|
20323
|
+
},
|
|
20324
|
+
{
|
|
20325
|
+
ipv4Prefix: "3.224.62.45/32"
|
|
20326
|
+
},
|
|
20327
|
+
{
|
|
20328
|
+
ipv4Prefix: "18.210.92.235/32"
|
|
20329
|
+
},
|
|
20330
|
+
{
|
|
20331
|
+
ipv4Prefix: "3.222.232.239/32"
|
|
20332
|
+
},
|
|
20333
|
+
{
|
|
20334
|
+
ipv4Prefix: "3.211.124.183/32"
|
|
20335
|
+
},
|
|
20336
|
+
{
|
|
20337
|
+
ipv4Prefix: "3.231.139.107/32"
|
|
20338
|
+
},
|
|
20339
|
+
{
|
|
20340
|
+
ipv4Prefix: "18.97.1.228/30"
|
|
20341
|
+
},
|
|
20342
|
+
{
|
|
20343
|
+
ipv4Prefix: "18.97.9.96/29"
|
|
20344
|
+
}
|
|
20345
|
+
]
|
|
20346
|
+
};
|
|
20347
|
+
|
|
20348
|
+
// ../integration-traffic/src/ip-verify.ts
|
|
20349
|
+
var RULE_ID_TO_RANGES = {
|
|
20350
|
+
// OpenAI — three separate published lists (training crawler vs
|
|
20351
|
+
// user-on-behalf fetcher vs search engine; OpenAI maintains the
|
|
20352
|
+
// split because the IPs really do differ between products).
|
|
20353
|
+
// src: https://openai.com/gptbot.json
|
|
20354
|
+
"openai-gptbot": gptbot_default,
|
|
20355
|
+
// src: https://openai.com/chatgpt-user.json
|
|
20356
|
+
"openai-chatgpt-user": chatgpt_user_default,
|
|
20357
|
+
// src: https://openai.com/searchbot.json
|
|
20358
|
+
"openai-searchbot": oai_searchbot_default,
|
|
20359
|
+
// Search engines.
|
|
20360
|
+
// src: https://developers.google.com/static/search/apis/ipranges/googlebot.json
|
|
20361
|
+
// (also covers Gemini grounding — Google doesn't publish a
|
|
20362
|
+
// separate Gemini list; Google-Extended traffic comes from the
|
|
20363
|
+
// same Googlebot ranges)
|
|
20364
|
+
"googlebot": googlebot_default,
|
|
20365
|
+
// src: https://www.bing.com/toolbox/bingbot.json
|
|
20366
|
+
// (also covers Copilot grounding — Microsoft routes Copilot's
|
|
20367
|
+
// web fetches through bingbot infrastructure)
|
|
20368
|
+
"bingbot": bingbot_default,
|
|
20369
|
+
// Perplexity — split between crawler and user-on-behalf fetcher,
|
|
20370
|
+
// same shape as OpenAI's split.
|
|
20371
|
+
// src: https://www.perplexity.ai/perplexitybot.json
|
|
20372
|
+
"perplexity-bot": perplexitybot_default,
|
|
20373
|
+
// src: https://www.perplexity.ai/perplexity-user.json
|
|
20374
|
+
"perplexity-user": perplexity_user_default,
|
|
20375
|
+
// Anthropic — no machine-readable JSON published. The bundled
|
|
20376
|
+
// anthropic.json is the set of networks registered to Anthropic,
|
|
20377
|
+
// PBC at ARIN (the authoritative allocation record). Maintained by
|
|
20378
|
+
// hand; refresh by re-querying the ARIN entity below. The crawler
|
|
20379
|
+
// block is AWS-ANTHROPIC 216.73.216.0/22 — empirical Cloud Run
|
|
20380
|
+
// logs show all real ClaudeBot traffic comes from there. Same raw
|
|
20381
|
+
// set is shared across every Claude-* UA the classifier emits.
|
|
20382
|
+
// src: https://rdap.arin.net/registry/entity/AP-2440
|
|
20383
|
+
"anthropic-claudebot": anthropic_default
|
|
20384
|
+
};
|
|
20385
|
+
var CACHE = (() => {
|
|
20386
|
+
const cache = /* @__PURE__ */ new Map();
|
|
20387
|
+
for (const [ruleId, raw] of Object.entries(RULE_ID_TO_RANGES)) {
|
|
20388
|
+
const parsed = [];
|
|
20389
|
+
for (const entry of raw.prefixes) {
|
|
20390
|
+
const cidr = entry.ipv4Prefix ?? entry.ipv6Prefix;
|
|
20391
|
+
if (!cidr) continue;
|
|
20392
|
+
const p = parseCidr(cidr);
|
|
20393
|
+
if (p) parsed.push(p);
|
|
20394
|
+
}
|
|
20395
|
+
cache.set(ruleId, parsed);
|
|
20396
|
+
}
|
|
20397
|
+
return cache;
|
|
20398
|
+
})();
|
|
20399
|
+
function parseIp(ip) {
|
|
20400
|
+
if (!ip) return null;
|
|
20401
|
+
const mappedMatch = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i.exec(ip);
|
|
20402
|
+
if (mappedMatch) return parseIp(mappedMatch[1]);
|
|
20403
|
+
if (ip.includes(":")) {
|
|
20404
|
+
const sides = ip.split("::");
|
|
20405
|
+
if (sides.length > 2) return null;
|
|
20406
|
+
const left = sides[0].length > 0 ? sides[0].split(":") : [];
|
|
20407
|
+
const right = sides.length === 2 && sides[1].length > 0 ? sides[1].split(":") : [];
|
|
20408
|
+
const groupCount = left.length + right.length;
|
|
20409
|
+
if (groupCount > 8) return null;
|
|
20410
|
+
if (sides.length === 1 && groupCount !== 8) return null;
|
|
20411
|
+
const fill = 8 - groupCount;
|
|
20412
|
+
const groups = [...left, ...new Array(fill).fill("0"), ...right];
|
|
20413
|
+
let addr2 = 0n;
|
|
20414
|
+
for (const g of groups) {
|
|
20415
|
+
if (g.length === 0 || g.length > 4) return null;
|
|
20416
|
+
const n = Number.parseInt(g, 16);
|
|
20417
|
+
if (!Number.isFinite(n) || n < 0 || n > 65535) return null;
|
|
20418
|
+
addr2 = addr2 << 16n | BigInt(n);
|
|
20419
|
+
}
|
|
20420
|
+
return { version: 6, addr: addr2 };
|
|
20421
|
+
}
|
|
20422
|
+
const octets = ip.split(".");
|
|
20423
|
+
if (octets.length !== 4) return null;
|
|
20424
|
+
let addr = 0n;
|
|
20425
|
+
for (const o of octets) {
|
|
20426
|
+
if (o.length === 0 || o.length > 3) return null;
|
|
20427
|
+
const n = Number.parseInt(o, 10);
|
|
20428
|
+
if (!Number.isInteger(n) || n < 0 || n > 255) return null;
|
|
20429
|
+
addr = addr << 8n | BigInt(n);
|
|
20430
|
+
}
|
|
20431
|
+
return { version: 4, addr };
|
|
20432
|
+
}
|
|
20433
|
+
function parseCidr(cidr) {
|
|
20434
|
+
const [ipPart, prefixStr] = cidr.split("/");
|
|
20435
|
+
if (!ipPart || !prefixStr) return null;
|
|
20436
|
+
const prefix = Number.parseInt(prefixStr, 10);
|
|
20437
|
+
if (!Number.isInteger(prefix)) return null;
|
|
20438
|
+
const parsed = parseIp(ipPart);
|
|
20439
|
+
if (!parsed) return null;
|
|
20440
|
+
const totalBits = parsed.version === 4 ? 32 : 128;
|
|
20441
|
+
if (prefix < 0 || prefix > totalBits) return null;
|
|
20442
|
+
const allOnes = (1n << BigInt(totalBits)) - 1n;
|
|
20443
|
+
const mask = allOnes >> BigInt(totalBits - prefix) << BigInt(totalBits - prefix);
|
|
20444
|
+
return {
|
|
20445
|
+
version: parsed.version,
|
|
20446
|
+
network: parsed.addr & mask,
|
|
20447
|
+
mask
|
|
20448
|
+
};
|
|
20449
|
+
}
|
|
20450
|
+
function verifyIpForRule(ip, ruleId) {
|
|
20451
|
+
if (!ip) return false;
|
|
20452
|
+
const ranges = CACHE.get(ruleId);
|
|
20453
|
+
if (!ranges || ranges.length === 0) return false;
|
|
20454
|
+
const parsed = parseIp(ip);
|
|
20455
|
+
if (!parsed) return false;
|
|
20456
|
+
for (const cidr of ranges) {
|
|
20457
|
+
if (parsed.version !== cidr.version) continue;
|
|
20458
|
+
if ((parsed.addr & cidr.mask) === cidr.network) return true;
|
|
20459
|
+
}
|
|
20460
|
+
return false;
|
|
20461
|
+
}
|
|
20462
|
+
|
|
20463
|
+
// ../integration-traffic/src/rules.ts
|
|
20464
|
+
var LEGACY_CHATGPT_DOMAIN = "chat.openai.com";
|
|
20465
|
+
var DEFAULT_AI_CRAWLER_RULES = [
|
|
20466
|
+
{
|
|
20467
|
+
id: "openai-gptbot",
|
|
20468
|
+
operator: "OpenAI",
|
|
20469
|
+
product: "GPTBot",
|
|
20470
|
+
purpose: "training",
|
|
20471
|
+
userAgentPatterns: [/GPTBot\//i]
|
|
20472
|
+
},
|
|
20473
|
+
{
|
|
20474
|
+
id: "openai-searchbot",
|
|
20475
|
+
operator: "OpenAI",
|
|
20476
|
+
product: "OAI-SearchBot",
|
|
20477
|
+
purpose: "search",
|
|
20478
|
+
userAgentPatterns: [/OAI-SearchBot\//i]
|
|
20479
|
+
},
|
|
20480
|
+
{
|
|
20481
|
+
id: "openai-chatgpt-user",
|
|
20482
|
+
operator: "OpenAI",
|
|
20483
|
+
product: "ChatGPT-User",
|
|
20484
|
+
purpose: "user-agent",
|
|
20485
|
+
userAgentPatterns: [/ChatGPT-User\//i]
|
|
20486
|
+
},
|
|
20487
|
+
{
|
|
20488
|
+
id: "anthropic-claudebot",
|
|
20489
|
+
operator: "Anthropic",
|
|
20490
|
+
product: "ClaudeBot",
|
|
20491
|
+
purpose: "training",
|
|
20492
|
+
// Anthropic ships several Claude-* crawlers (ClaudeBot for training,
|
|
20493
|
+
// Claude-Web for chat fetches, Claude-SearchBot for search). The
|
|
20494
|
+
// `Claude-` prefix + `Bot/` suffix is the stable shape — pattern is
|
|
20495
|
+
// permissive enough to catch new Claude-* variants as Anthropic
|
|
20496
|
+
// adds them, without matching unrelated UAs that happen to mention
|
|
20497
|
+
// "claude".
|
|
20498
|
+
userAgentPatterns: [
|
|
20499
|
+
/ClaudeBot\//i,
|
|
20500
|
+
/Claude-Web\//i,
|
|
20501
|
+
/Claude-SearchBot\//i,
|
|
20502
|
+
/Claude-[A-Z]+Bot\//i,
|
|
20503
|
+
/anthropic-ai/i
|
|
20504
|
+
]
|
|
20505
|
+
},
|
|
20506
|
+
{
|
|
20507
|
+
id: "perplexity-bot",
|
|
20508
|
+
operator: "Perplexity",
|
|
20509
|
+
product: "PerplexityBot",
|
|
20510
|
+
purpose: "search",
|
|
20511
|
+
userAgentPatterns: [/PerplexityBot\//i]
|
|
20512
|
+
},
|
|
20513
|
+
{
|
|
20514
|
+
// User-initiated fetches when a Perplexity user opens a citation
|
|
20515
|
+
// link. Separate from PerplexityBot (crawl) — different ranges and
|
|
20516
|
+
// different operational signal. Perplexity publishes both UA
|
|
20517
|
+
// patterns at perplexity.ai/perplexity-user.json.
|
|
20518
|
+
id: "perplexity-user",
|
|
20519
|
+
operator: "Perplexity",
|
|
20520
|
+
product: "Perplexity-User",
|
|
20521
|
+
purpose: "user-agent",
|
|
20522
|
+
userAgentPatterns: [/Perplexity-User\//i]
|
|
20523
|
+
},
|
|
20524
|
+
{
|
|
20525
|
+
id: "google-extended",
|
|
20526
|
+
operator: "Google",
|
|
20527
|
+
product: "Google-Extended",
|
|
20528
|
+
purpose: "training-control",
|
|
20529
|
+
userAgentPatterns: [/Google-Extended/i]
|
|
20530
|
+
},
|
|
20531
|
+
{
|
|
20532
|
+
id: "bytespider",
|
|
20533
|
+
operator: "ByteDance",
|
|
20534
|
+
product: "Bytespider",
|
|
20535
|
+
purpose: "training",
|
|
20536
|
+
userAgentPatterns: [/Bytespider/i]
|
|
20537
|
+
},
|
|
20538
|
+
{
|
|
20539
|
+
id: "applebot-extended",
|
|
20540
|
+
operator: "Apple",
|
|
20541
|
+
product: "Applebot-Extended",
|
|
20542
|
+
purpose: "training",
|
|
20543
|
+
userAgentPatterns: [/Applebot-Extended/i]
|
|
20544
|
+
},
|
|
20545
|
+
{
|
|
20546
|
+
// Apple's general crawler (separate from Applebot-Extended, which is
|
|
20547
|
+
// the training-opt-out signaling UA). Both indexes pages for Apple
|
|
20548
|
+
// services (Siri/Spotlight); only Applebot-Extended is gated by
|
|
20549
|
+
// training-data opt-out.
|
|
20550
|
+
id: "applebot",
|
|
20551
|
+
operator: "Apple",
|
|
20552
|
+
product: "Applebot",
|
|
20553
|
+
purpose: "crawl",
|
|
20554
|
+
userAgentPatterns: [/Applebot\//i]
|
|
20555
|
+
},
|
|
20556
|
+
{
|
|
20557
|
+
id: "meta-externalagent",
|
|
20558
|
+
operator: "Meta",
|
|
20559
|
+
product: "meta-externalagent",
|
|
20560
|
+
purpose: "training",
|
|
20561
|
+
userAgentPatterns: [/meta-externalagent/i]
|
|
20562
|
+
},
|
|
20563
|
+
{
|
|
20564
|
+
id: "ccbot",
|
|
20565
|
+
operator: "Common Crawl",
|
|
20566
|
+
product: "CCBot",
|
|
20567
|
+
purpose: "crawl",
|
|
20568
|
+
userAgentPatterns: [/CCBot\//i]
|
|
20569
|
+
},
|
|
20570
|
+
{
|
|
20571
|
+
id: "cohere-ai",
|
|
20572
|
+
operator: "Cohere",
|
|
20573
|
+
product: "cohere-ai",
|
|
20574
|
+
purpose: "training",
|
|
20575
|
+
userAgentPatterns: [/cohere-ai/i]
|
|
20576
|
+
},
|
|
20577
|
+
{
|
|
20578
|
+
id: "diffbot",
|
|
20579
|
+
operator: "Diffbot",
|
|
20580
|
+
product: "Diffbot",
|
|
20581
|
+
purpose: "crawl",
|
|
20582
|
+
userAgentPatterns: [/Diffbot/i]
|
|
20583
|
+
},
|
|
20584
|
+
{
|
|
20585
|
+
id: "mistral-ai",
|
|
20586
|
+
operator: "Mistral AI",
|
|
20587
|
+
product: "MistralAI-User",
|
|
20588
|
+
purpose: "crawl",
|
|
20589
|
+
// Mistral ships both `MistralAI-User/*` (chat-on-behalf-of-user
|
|
20590
|
+
// fetches) and `MistralBot/*` (general crawler). Earlier rule only
|
|
20591
|
+
// matched `MistralAI` and missed the bot — caught on 2026-05-18
|
|
20592
|
+
// when canonry.ai/canonry-landing's classification chart went flat
|
|
20593
|
+
// and the bot UA was sitting in the `unknown` bucket.
|
|
20594
|
+
userAgentPatterns: [/MistralAI/i, /MistralBot/i]
|
|
20595
|
+
},
|
|
20596
|
+
{
|
|
20597
|
+
id: "deepseek",
|
|
20598
|
+
operator: "DeepSeek",
|
|
20599
|
+
product: "DeepSeekBot",
|
|
20600
|
+
purpose: "training",
|
|
20601
|
+
userAgentPatterns: [/DeepSeekBot/i]
|
|
20602
|
+
},
|
|
20603
|
+
// Classic search-engine crawlers. Not strictly "AI" by training origin,
|
|
20604
|
+
// but the same audience: machine traffic indexing the site for query
|
|
20605
|
+
// surfaces. Operators tracking AI visibility want this signal too —
|
|
20606
|
+
// SERP indexing is the upstream that feeds AI answer engines (Bing
|
|
20607
|
+
// powers ChatGPT search; Google powers Gemini grounding). Classified
|
|
20608
|
+
// alongside LLM crawlers; the dashboard's "AI crawler hits" label is
|
|
20609
|
+
// imprecise here but functionally correct (these are still bots, not
|
|
20610
|
+
// humans).
|
|
20611
|
+
{
|
|
20612
|
+
id: "googlebot",
|
|
20613
|
+
operator: "Google",
|
|
20614
|
+
product: "Googlebot",
|
|
20615
|
+
purpose: "search",
|
|
20616
|
+
// Googlebot has Smartphone / Desktop / Image / News / Video variants.
|
|
20617
|
+
// All match the `Googlebot/` prefix on first appearance in the UA.
|
|
20618
|
+
// Excludes `Googlebot-Image` etc. that ride a `Googlebot-` prefix —
|
|
20619
|
+
// they also match `Googlebot/` in their UA strings.
|
|
20620
|
+
userAgentPatterns: [/Googlebot[/-]/i]
|
|
20621
|
+
},
|
|
20622
|
+
{
|
|
20623
|
+
id: "bingbot",
|
|
20624
|
+
operator: "Microsoft",
|
|
20625
|
+
product: "bingbot",
|
|
20626
|
+
purpose: "search",
|
|
20627
|
+
userAgentPatterns: [/bingbot\//i]
|
|
20628
|
+
},
|
|
20629
|
+
{
|
|
20630
|
+
id: "duckduckbot",
|
|
20631
|
+
operator: "DuckDuckGo",
|
|
20632
|
+
product: "DuckDuckBot",
|
|
20633
|
+
purpose: "search",
|
|
20634
|
+
userAgentPatterns: [/DuckDuckBot/i]
|
|
20635
|
+
},
|
|
20636
|
+
{
|
|
20637
|
+
id: "yandexbot",
|
|
20638
|
+
operator: "Yandex",
|
|
20639
|
+
product: "YandexBot",
|
|
20640
|
+
purpose: "search",
|
|
20641
|
+
userAgentPatterns: [/YandexBot\//i]
|
|
20642
|
+
},
|
|
20643
|
+
{
|
|
20644
|
+
id: "baiduspider",
|
|
20645
|
+
operator: "Baidu",
|
|
20646
|
+
product: "Baiduspider",
|
|
20647
|
+
purpose: "search",
|
|
20648
|
+
userAgentPatterns: [/Baiduspider/i]
|
|
20649
|
+
},
|
|
20650
|
+
{
|
|
20651
|
+
id: "amazonbot",
|
|
20652
|
+
operator: "Amazon",
|
|
20653
|
+
product: "Amazonbot",
|
|
20654
|
+
purpose: "crawl",
|
|
20655
|
+
userAgentPatterns: [/Amazonbot\//i]
|
|
20656
|
+
}
|
|
20657
|
+
];
|
|
20658
|
+
var DEFAULT_AI_REFERRER_RULES = [
|
|
20659
|
+
{ domain: AI_ENGINE_DOMAINS.chatgpt, operator: "OpenAI", product: "ChatGPT" },
|
|
20660
|
+
{ domain: LEGACY_CHATGPT_DOMAIN, operator: "OpenAI", product: "ChatGPT" },
|
|
20661
|
+
{ domain: AI_ENGINE_DOMAINS.perplexity, operator: "Perplexity", product: "Perplexity" },
|
|
20662
|
+
{ domain: AI_ENGINE_DOMAINS.claude, operator: "Anthropic", product: "Claude" },
|
|
20663
|
+
{ domain: AI_ENGINE_DOMAINS.gemini, operator: "Google", product: "Gemini" },
|
|
20664
|
+
{ domain: AI_ENGINE_DOMAINS.copilotMicrosoft, operator: "Microsoft", product: "Copilot" },
|
|
20665
|
+
{ domain: AI_ENGINE_DOMAINS.phind, operator: "Phind", product: "Phind" },
|
|
20666
|
+
{ domain: AI_ENGINE_DOMAINS.you, operator: "You.com", product: "You.com" },
|
|
20667
|
+
{ domain: AI_ENGINE_DOMAINS.metaAi, operator: "Meta", product: "Meta AI" }
|
|
20668
|
+
];
|
|
20669
|
+
|
|
20670
|
+
// ../integration-traffic/src/classifier.ts
|
|
20671
|
+
function normalizeHost(host) {
|
|
20672
|
+
return host.trim().toLowerCase().replace(/^www\./, "");
|
|
20673
|
+
}
|
|
20674
|
+
function hostMatches(host, domain) {
|
|
20675
|
+
const normalizedHost = normalizeHost(host);
|
|
20676
|
+
const normalizedDomain = normalizeHost(domain);
|
|
20677
|
+
return normalizedHost === normalizedDomain || normalizedHost.endsWith(`.${normalizedDomain}`);
|
|
20678
|
+
}
|
|
20679
|
+
function utmTokenMatchesDomain(utmSource, domain) {
|
|
20680
|
+
if (hostMatches(utmSource, domain)) return true;
|
|
20681
|
+
const normalizedUtm = normalizeHost(utmSource);
|
|
20682
|
+
const firstLabel = normalizeHost(domain).split(".")[0];
|
|
20683
|
+
return Boolean(firstLabel) && normalizedUtm === firstLabel;
|
|
20684
|
+
}
|
|
20685
|
+
function hostFromUrl(value) {
|
|
20686
|
+
if (!value) return null;
|
|
18258
20687
|
try {
|
|
18259
20688
|
return normalizeHost(new URL(value).hostname);
|
|
18260
20689
|
} catch {
|
|
@@ -18280,12 +20709,13 @@ function classifyCrawler(event) {
|
|
|
18280
20709
|
if (!userAgent) return null;
|
|
18281
20710
|
for (const rule of DEFAULT_AI_CRAWLER_RULES) {
|
|
18282
20711
|
if (rule.userAgentPatterns.some((pattern) => pattern.test(userAgent))) {
|
|
20712
|
+
const verified = verifyIpForRule(event.remoteIp, rule.id);
|
|
18283
20713
|
return {
|
|
18284
20714
|
botId: rule.id,
|
|
18285
20715
|
operator: rule.operator,
|
|
18286
20716
|
product: rule.product,
|
|
18287
20717
|
purpose: rule.purpose,
|
|
18288
|
-
verificationStatus: "claimed_unverified",
|
|
20718
|
+
verificationStatus: verified ? "verified" : "claimed_unverified",
|
|
18289
20719
|
matchedUserAgent: userAgent
|
|
18290
20720
|
};
|
|
18291
20721
|
}
|
|
@@ -20736,6 +23166,79 @@ var providersConfiguredCheck = {
|
|
|
20736
23166
|
};
|
|
20737
23167
|
var PROVIDERS_CHECKS = [providersConfiguredCheck];
|
|
20738
23168
|
|
|
23169
|
+
// ../api-routes/src/doctor/checks/runtime-state.ts
|
|
23170
|
+
import fs7 from "fs";
|
|
23171
|
+
var dbFilePresentCheck = {
|
|
23172
|
+
id: "db.file.present",
|
|
23173
|
+
category: CheckCategories.database,
|
|
23174
|
+
scope: CheckScopes.global,
|
|
23175
|
+
title: "Database file present",
|
|
23176
|
+
run: (ctx) => {
|
|
23177
|
+
const path16 = ctx.runtimeStatePaths?.databasePath;
|
|
23178
|
+
if (!path16) {
|
|
23179
|
+
return {
|
|
23180
|
+
status: CheckStatuses.skipped,
|
|
23181
|
+
code: "db.file.path-not-wired",
|
|
23182
|
+
summary: "No database file path configured for this deployment (cloud DB).",
|
|
23183
|
+
remediation: null
|
|
23184
|
+
};
|
|
23185
|
+
}
|
|
23186
|
+
if (!fs7.existsSync(path16)) {
|
|
23187
|
+
return {
|
|
23188
|
+
status: CheckStatuses.fail,
|
|
23189
|
+
code: "db.file.missing",
|
|
23190
|
+
summary: `Database file at \`${path16}\` has been deleted while the daemon is running.`,
|
|
23191
|
+
remediation: "Restart `canonry serve` so a fresh database is created and migrations re-run. Until you do, the daemon will keep serving stale data from a deleted-but-open file handle and writes will be lost.",
|
|
23192
|
+
details: { path: path16 }
|
|
23193
|
+
};
|
|
23194
|
+
}
|
|
23195
|
+
return {
|
|
23196
|
+
status: CheckStatuses.ok,
|
|
23197
|
+
code: "db.file.present",
|
|
23198
|
+
summary: `Database file present at \`${path16}\`.`,
|
|
23199
|
+
remediation: null,
|
|
23200
|
+
details: { path: path16 }
|
|
23201
|
+
};
|
|
23202
|
+
}
|
|
23203
|
+
};
|
|
23204
|
+
var configFilePresentCheck = {
|
|
23205
|
+
id: "config.file.present",
|
|
23206
|
+
category: CheckCategories.config,
|
|
23207
|
+
scope: CheckScopes.global,
|
|
23208
|
+
title: "Config file present",
|
|
23209
|
+
run: (ctx) => {
|
|
23210
|
+
const path16 = ctx.runtimeStatePaths?.configPath;
|
|
23211
|
+
if (!path16) {
|
|
23212
|
+
return {
|
|
23213
|
+
status: CheckStatuses.skipped,
|
|
23214
|
+
code: "config.file.path-not-wired",
|
|
23215
|
+
summary: "No config file path configured for this deployment.",
|
|
23216
|
+
remediation: null
|
|
23217
|
+
};
|
|
23218
|
+
}
|
|
23219
|
+
if (!fs7.existsSync(path16)) {
|
|
23220
|
+
return {
|
|
23221
|
+
status: CheckStatuses.fail,
|
|
23222
|
+
code: "config.file.missing",
|
|
23223
|
+
summary: `Config file at \`${path16}\` has been deleted while the daemon is running.`,
|
|
23224
|
+
remediation: "Restart `canonry serve` after the file is restored (provider keys, OAuth tokens, and integration credentials live in this file; the in-memory copy is read-only until restart).",
|
|
23225
|
+
details: { path: path16 }
|
|
23226
|
+
};
|
|
23227
|
+
}
|
|
23228
|
+
return {
|
|
23229
|
+
status: CheckStatuses.ok,
|
|
23230
|
+
code: "config.file.present",
|
|
23231
|
+
summary: `Config file present at \`${path16}\`.`,
|
|
23232
|
+
remediation: null,
|
|
23233
|
+
details: { path: path16 }
|
|
23234
|
+
};
|
|
23235
|
+
}
|
|
23236
|
+
};
|
|
23237
|
+
var RUNTIME_STATE_CHECKS = [
|
|
23238
|
+
dbFilePresentCheck,
|
|
23239
|
+
configFilePresentCheck
|
|
23240
|
+
];
|
|
23241
|
+
|
|
20739
23242
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
20740
23243
|
import { and as and20, eq as eq25, gte as gte4, ne as ne4, sql as sql11 } from "drizzle-orm";
|
|
20741
23244
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
@@ -21041,6 +23544,9 @@ var TRAFFIC_SOURCE_CHECKS = [
|
|
|
21041
23544
|
|
|
21042
23545
|
// ../api-routes/src/doctor/registry.ts
|
|
21043
23546
|
var ALL_CHECKS = [
|
|
23547
|
+
// Runtime-state checks run first so file-system gone errors surface
|
|
23548
|
+
// before any auth/integration checks try to touch the (orphaned) DB.
|
|
23549
|
+
...RUNTIME_STATE_CHECKS,
|
|
21044
23550
|
...GOOGLE_AUTH_CHECKS,
|
|
21045
23551
|
...BING_AUTH_CHECKS,
|
|
21046
23552
|
...GA_AUTH_CHECKS,
|
|
@@ -21131,7 +23637,8 @@ async function doctorRoutes(app, opts) {
|
|
|
21131
23637
|
getGoogleAuthConfig: opts.getGoogleAuthConfig,
|
|
21132
23638
|
redirectUri,
|
|
21133
23639
|
providerSummary: opts.providerSummary,
|
|
21134
|
-
trafficSourceValidators: opts.trafficSourceValidators
|
|
23640
|
+
trafficSourceValidators: opts.trafficSourceValidators,
|
|
23641
|
+
runtimeStatePaths: opts.runtimeStatePaths
|
|
21135
23642
|
};
|
|
21136
23643
|
return runChecks(ctx, ALL_CHECKS, { checkIds });
|
|
21137
23644
|
});
|
|
@@ -21152,7 +23659,8 @@ async function doctorRoutes(app, opts) {
|
|
|
21152
23659
|
getGoogleAuthConfig: opts.getGoogleAuthConfig,
|
|
21153
23660
|
redirectUri,
|
|
21154
23661
|
providerSummary: opts.providerSummary,
|
|
21155
|
-
trafficSourceValidators: opts.trafficSourceValidators
|
|
23662
|
+
trafficSourceValidators: opts.trafficSourceValidators,
|
|
23663
|
+
runtimeStatePaths: opts.runtimeStatePaths
|
|
21156
23664
|
};
|
|
21157
23665
|
return runChecks(ctx, ALL_CHECKS, { checkIds });
|
|
21158
23666
|
});
|
|
@@ -21641,6 +24149,21 @@ async function apiRoutes(app, opts) {
|
|
|
21641
24149
|
}
|
|
21642
24150
|
});
|
|
21643
24151
|
});
|
|
24152
|
+
if (opts.runtimeStatePaths) {
|
|
24153
|
+
const { databasePath, configPath } = opts.runtimeStatePaths;
|
|
24154
|
+
const isDiagnosticUrl = (url) => url === "/health" || /\/doctor(?:\?|$)/.test(url);
|
|
24155
|
+
app.addHook("onRequest", async (request) => {
|
|
24156
|
+
if (isDiagnosticUrl(request.url)) return;
|
|
24157
|
+
const missing = [];
|
|
24158
|
+
if (!fs8.existsSync(databasePath)) missing.push(`database file \`${databasePath}\``);
|
|
24159
|
+
if (configPath && !fs8.existsSync(configPath)) missing.push(`config file \`${configPath}\``);
|
|
24160
|
+
if (missing.length === 0) return;
|
|
24161
|
+
throw runtimeStateMissing(
|
|
24162
|
+
`Runtime state missing: ${missing.join(" and ")}. Restart \`canonry serve\` so a fresh state is created (the daemon's open file handles still point at the deleted inode, so writes are being lost).`,
|
|
24163
|
+
{ missing }
|
|
24164
|
+
);
|
|
24165
|
+
});
|
|
24166
|
+
}
|
|
21644
24167
|
await app.register(async (api) => {
|
|
21645
24168
|
if (!opts.skipAuth) {
|
|
21646
24169
|
await authPlugin(api, {
|
|
@@ -21764,7 +24287,8 @@ async function apiRoutes(app, opts) {
|
|
|
21764
24287
|
getGoogleAuthConfig: opts.getGoogleAuthConfig,
|
|
21765
24288
|
publicUrl: opts.publicUrl,
|
|
21766
24289
|
providerSummary: opts.providerSummary,
|
|
21767
|
-
trafficSourceValidators: buildTrafficSourceValidators(opts)
|
|
24290
|
+
trafficSourceValidators: buildTrafficSourceValidators(opts),
|
|
24291
|
+
runtimeStatePaths: opts.runtimeStatePaths
|
|
21768
24292
|
});
|
|
21769
24293
|
if (opts.registerAuthenticatedRoutes) {
|
|
21770
24294
|
await opts.registerAuthenticatedRoutes(api);
|
|
@@ -21950,7 +24474,7 @@ async function withRetry(fn, options = {}) {
|
|
|
21950
24474
|
}
|
|
21951
24475
|
|
|
21952
24476
|
// ../provider-gemini/src/normalize.ts
|
|
21953
|
-
var DEFAULT_MODEL = "gemini-
|
|
24477
|
+
var DEFAULT_MODEL = "gemini-2.5-flash";
|
|
21954
24478
|
function isVertexConfig(config) {
|
|
21955
24479
|
return !!config.vertexProject;
|
|
21956
24480
|
}
|
|
@@ -22287,15 +24811,14 @@ var geminiAdapter = {
|
|
|
22287
24811
|
keyUrl: "https://aistudio.google.com/apikey",
|
|
22288
24812
|
// Upstream model list: https://ai.google.dev/gemini-api/docs/models
|
|
22289
24813
|
modelRegistry: {
|
|
22290
|
-
defaultModel: "gemini-
|
|
24814
|
+
defaultModel: "gemini-2.5-flash",
|
|
22291
24815
|
validationPattern: /./,
|
|
22292
|
-
validationHint: "any valid Google model name (e.g. gemini-
|
|
24816
|
+
validationHint: "any valid Google model name (e.g. gemini-2.5-flash, learnlm-1.5-pro-experimental)",
|
|
22293
24817
|
knownModels: [
|
|
22294
|
-
{ id: "gemini-
|
|
22295
|
-
{ id: "gemini-
|
|
22296
|
-
{ id: "gemini-
|
|
22297
|
-
{ id: "gemini-
|
|
22298
|
-
{ id: "gemini-2.5-flash", displayName: "Gemini 2.5 Flash", tier: "standard" }
|
|
24818
|
+
{ id: "gemini-2.5-pro", displayName: "Gemini 2.5 Pro", tier: "flagship" },
|
|
24819
|
+
{ id: "gemini-2.5-flash", displayName: "Gemini 2.5 Flash", tier: "standard" },
|
|
24820
|
+
{ id: "gemini-2.5-flash-lite", displayName: "Gemini 2.5 Flash-Lite", tier: "economy" },
|
|
24821
|
+
{ id: "gemini-2.0-flash", displayName: "Gemini 2.0 Flash", tier: "standard" }
|
|
22299
24822
|
]
|
|
22300
24823
|
},
|
|
22301
24824
|
validateConfig(config) {
|
|
@@ -23711,12 +26234,12 @@ function sleep2(ms) {
|
|
|
23711
26234
|
}
|
|
23712
26235
|
|
|
23713
26236
|
// ../provider-cdp/src/screenshot.ts
|
|
23714
|
-
import
|
|
26237
|
+
import fs9 from "fs";
|
|
23715
26238
|
import path8 from "path";
|
|
23716
26239
|
async function captureElementScreenshot(client, selector, outputPath) {
|
|
23717
26240
|
const dir = path8.dirname(outputPath);
|
|
23718
|
-
if (!
|
|
23719
|
-
|
|
26241
|
+
if (!fs9.existsSync(dir)) {
|
|
26242
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
23720
26243
|
}
|
|
23721
26244
|
let clip;
|
|
23722
26245
|
try {
|
|
@@ -23750,7 +26273,7 @@ async function captureElementScreenshot(client, selector, outputPath) {
|
|
|
23750
26273
|
}
|
|
23751
26274
|
const { data } = await client.Page.captureScreenshot(screenshotParams);
|
|
23752
26275
|
const buffer = Buffer.from(data, "base64");
|
|
23753
|
-
|
|
26276
|
+
fs9.writeFileSync(outputPath, buffer);
|
|
23754
26277
|
return outputPath;
|
|
23755
26278
|
}
|
|
23756
26279
|
|
|
@@ -24508,7 +27031,7 @@ function removeWordpressConnection(config, projectName) {
|
|
|
24508
27031
|
|
|
24509
27032
|
// src/job-runner.ts
|
|
24510
27033
|
import crypto25 from "crypto";
|
|
24511
|
-
import
|
|
27034
|
+
import fs10 from "fs";
|
|
24512
27035
|
import path10 from "path";
|
|
24513
27036
|
import os5 from "os";
|
|
24514
27037
|
import { and as and22, eq as eq28, inArray as inArray10, sql as sql12 } from "drizzle-orm";
|
|
@@ -25002,12 +27525,12 @@ var JobRunner = class {
|
|
|
25002
27525
|
allBrandNames
|
|
25003
27526
|
);
|
|
25004
27527
|
let screenshotRelPath = null;
|
|
25005
|
-
if (raw.screenshotPath &&
|
|
27528
|
+
if (raw.screenshotPath && fs10.existsSync(raw.screenshotPath)) {
|
|
25006
27529
|
const snapshotId = crypto25.randomUUID();
|
|
25007
27530
|
const screenshotDir = path10.join(os5.homedir(), ".canonry", "screenshots", runId);
|
|
25008
|
-
if (!
|
|
27531
|
+
if (!fs10.existsSync(screenshotDir)) fs10.mkdirSync(screenshotDir, { recursive: true });
|
|
25009
27532
|
const destPath = path10.join(screenshotDir, `${snapshotId}.png`);
|
|
25010
|
-
|
|
27533
|
+
fs10.renameSync(raw.screenshotPath, destPath);
|
|
25011
27534
|
screenshotRelPath = `${runId}/${snapshotId}.png`;
|
|
25012
27535
|
this.db.insert(querySnapshots).values({
|
|
25013
27536
|
id: snapshotId,
|
|
@@ -26045,7 +28568,7 @@ function computeSummary(rows) {
|
|
|
26045
28568
|
|
|
26046
28569
|
// src/backlink-extract.ts
|
|
26047
28570
|
import crypto30 from "crypto";
|
|
26048
|
-
import
|
|
28571
|
+
import fs11 from "fs";
|
|
26049
28572
|
import { and as and26, desc as desc16, eq as eq33 } from "drizzle-orm";
|
|
26050
28573
|
var log7 = createLogger("BacklinkExtract");
|
|
26051
28574
|
function defaultDeps2() {
|
|
@@ -26074,7 +28597,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
|
|
|
26074
28597
|
if (!sync.vertexPath || !sync.edgesPath) {
|
|
26075
28598
|
throw new Error(`Release ${sync.release} is missing cached file paths`);
|
|
26076
28599
|
}
|
|
26077
|
-
if (!
|
|
28600
|
+
if (!fs11.existsSync(sync.vertexPath) || !fs11.existsSync(sync.edgesPath)) {
|
|
26078
28601
|
throw new Error(
|
|
26079
28602
|
`Cache for release ${sync.release} is missing from disk (expected at ${sync.vertexPath}). The sync record exists in the database, but the ~16 GB dump was deleted or never present on this machine. Re-sync this release from the Backlinks admin page to restore the cache.`
|
|
26080
28603
|
);
|
|
@@ -26465,7 +28988,7 @@ function buildDiscoveryInsightTitle(input) {
|
|
|
26465
28988
|
}
|
|
26466
28989
|
|
|
26467
28990
|
// src/commands/backfill.ts
|
|
26468
|
-
import { and as and28, eq as eq35, inArray as inArray11 } from "drizzle-orm";
|
|
28991
|
+
import { and as and28, eq as eq35, inArray as inArray11, isNull, sql as sql15 } from "drizzle-orm";
|
|
26469
28992
|
var SNAPSHOT_BATCH_SIZE = 500;
|
|
26470
28993
|
async function backfillAnswerVisibilityCommand(opts) {
|
|
26471
28994
|
const config = loadConfig();
|
|
@@ -26922,7 +29445,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
26922
29445
|
return result;
|
|
26923
29446
|
}
|
|
26924
29447
|
async function backfillInsightsCommand(project, opts) {
|
|
26925
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
29448
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-2XL2M7QP.js");
|
|
26926
29449
|
const config = loadConfig();
|
|
26927
29450
|
const db = createClient(config.database);
|
|
26928
29451
|
migrate(db);
|
|
@@ -26970,6 +29493,247 @@ Backfill ${isDryRun ? "preview" : "complete"}.`);
|
|
|
26970
29493
|
console.log(` No DB writes performed. Re-run without --dry-run to apply.`);
|
|
26971
29494
|
}
|
|
26972
29495
|
}
|
|
29496
|
+
function replayQueryAuditLog(events) {
|
|
29497
|
+
const active = [];
|
|
29498
|
+
for (const ev of events) {
|
|
29499
|
+
let diff;
|
|
29500
|
+
try {
|
|
29501
|
+
diff = ev.diff ? JSON.parse(ev.diff) : {};
|
|
29502
|
+
} catch {
|
|
29503
|
+
continue;
|
|
29504
|
+
}
|
|
29505
|
+
if (ev.action === "keywords.appended" || ev.action === "queries.appended") {
|
|
29506
|
+
const added = Array.isArray(diff.added) ? diff.added : [];
|
|
29507
|
+
for (const q of added) {
|
|
29508
|
+
active.push({ text: q, addedAt: ev.createdAt, deletedAt: null });
|
|
29509
|
+
}
|
|
29510
|
+
} else if (ev.action === "keywords.deleted" || ev.action === "queries.deleted") {
|
|
29511
|
+
const deleted = Array.isArray(diff.deleted) ? diff.deleted : [];
|
|
29512
|
+
for (const q of deleted) {
|
|
29513
|
+
for (let i = active.length - 1; i >= 0; i--) {
|
|
29514
|
+
if (active[i].text === q && active[i].deletedAt === null) {
|
|
29515
|
+
active[i].deletedAt = ev.createdAt;
|
|
29516
|
+
break;
|
|
29517
|
+
}
|
|
29518
|
+
}
|
|
29519
|
+
}
|
|
29520
|
+
} else if (ev.action === "queries.replaced") {
|
|
29521
|
+
const newSet = Array.isArray(diff.queries) ? diff.queries : [];
|
|
29522
|
+
for (const e of active) {
|
|
29523
|
+
if (e.deletedAt === null) e.deletedAt = ev.createdAt;
|
|
29524
|
+
}
|
|
29525
|
+
for (const q of newSet) {
|
|
29526
|
+
active.push({ text: q, addedAt: ev.createdAt, deletedAt: null });
|
|
29527
|
+
}
|
|
29528
|
+
}
|
|
29529
|
+
}
|
|
29530
|
+
return active;
|
|
29531
|
+
}
|
|
29532
|
+
function activeQueriesAt(history, t) {
|
|
29533
|
+
return history.filter((e) => e.addedAt <= t && (e.deletedAt === null || e.deletedAt > t)).map((e) => e.text);
|
|
29534
|
+
}
|
|
29535
|
+
var CONTENT_MATCH_STOPWORDS = /* @__PURE__ */ new Set([
|
|
29536
|
+
"the",
|
|
29537
|
+
"a",
|
|
29538
|
+
"an",
|
|
29539
|
+
"and",
|
|
29540
|
+
"or",
|
|
29541
|
+
"but",
|
|
29542
|
+
"is",
|
|
29543
|
+
"are",
|
|
29544
|
+
"was",
|
|
29545
|
+
"were",
|
|
29546
|
+
"be",
|
|
29547
|
+
"been",
|
|
29548
|
+
"being",
|
|
29549
|
+
"have",
|
|
29550
|
+
"has",
|
|
29551
|
+
"had",
|
|
29552
|
+
"do",
|
|
29553
|
+
"does",
|
|
29554
|
+
"did",
|
|
29555
|
+
"will",
|
|
29556
|
+
"would",
|
|
29557
|
+
"could",
|
|
29558
|
+
"should",
|
|
29559
|
+
"may",
|
|
29560
|
+
"might",
|
|
29561
|
+
"can",
|
|
29562
|
+
"this",
|
|
29563
|
+
"that",
|
|
29564
|
+
"these",
|
|
29565
|
+
"those",
|
|
29566
|
+
"i",
|
|
29567
|
+
"you",
|
|
29568
|
+
"he",
|
|
29569
|
+
"she",
|
|
29570
|
+
"it",
|
|
29571
|
+
"we",
|
|
29572
|
+
"they",
|
|
29573
|
+
"what",
|
|
29574
|
+
"which",
|
|
29575
|
+
"who",
|
|
29576
|
+
"how",
|
|
29577
|
+
"why",
|
|
29578
|
+
"when",
|
|
29579
|
+
"where",
|
|
29580
|
+
"with",
|
|
29581
|
+
"for",
|
|
29582
|
+
"from",
|
|
29583
|
+
"of",
|
|
29584
|
+
"in",
|
|
29585
|
+
"on",
|
|
29586
|
+
"at",
|
|
29587
|
+
"to",
|
|
29588
|
+
"by",
|
|
29589
|
+
"as",
|
|
29590
|
+
"best",
|
|
29591
|
+
"most"
|
|
29592
|
+
]);
|
|
29593
|
+
function tokenizeForMatch(s) {
|
|
29594
|
+
return s.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((t) => t.length >= 3 && !CONTENT_MATCH_STOPWORDS.has(t));
|
|
29595
|
+
}
|
|
29596
|
+
function contentMatchScore(queryText, answerText) {
|
|
29597
|
+
const queryTokens = [...new Set(tokenizeForMatch(queryText))];
|
|
29598
|
+
if (queryTokens.length === 0) return 0;
|
|
29599
|
+
const answerHead = answerText.slice(0, 300).toLowerCase();
|
|
29600
|
+
const hit = queryTokens.filter((t) => answerHead.includes(t)).length;
|
|
29601
|
+
return hit / queryTokens.length;
|
|
29602
|
+
}
|
|
29603
|
+
async function backfillSnapshotAttributionCommand(opts) {
|
|
29604
|
+
const config = loadConfig();
|
|
29605
|
+
const db = createClient(config.database);
|
|
29606
|
+
migrate(db);
|
|
29607
|
+
const project = db.select().from(projects).where(eq35(projects.name, opts.project)).get();
|
|
29608
|
+
if (!project) {
|
|
29609
|
+
throw new Error(`Project "${opts.project}" not found`);
|
|
29610
|
+
}
|
|
29611
|
+
const isJson = opts.format === "json";
|
|
29612
|
+
const isDryRun = opts.dryRun === true;
|
|
29613
|
+
if (!isJson) {
|
|
29614
|
+
const mode = isDryRun ? " [DRY RUN \u2014 no writes]" : "";
|
|
29615
|
+
process.stderr.write(`Recovering orphan snapshot attribution for "${project.name}"${mode}...
|
|
29616
|
+
`);
|
|
29617
|
+
}
|
|
29618
|
+
const events = db.select({ createdAt: auditLog.createdAt, action: auditLog.action, diff: auditLog.diff }).from(auditLog).where(and28(
|
|
29619
|
+
eq35(auditLog.projectId, project.id),
|
|
29620
|
+
inArray11(auditLog.action, ["keywords.appended", "keywords.deleted", "queries.appended", "queries.deleted", "queries.replaced"])
|
|
29621
|
+
)).orderBy(auditLog.createdAt).all();
|
|
29622
|
+
const history = replayQueryAuditLog(events);
|
|
29623
|
+
const orphanRuns = db.select({
|
|
29624
|
+
runId: runs.id,
|
|
29625
|
+
createdAt: runs.createdAt,
|
|
29626
|
+
location: runs.location
|
|
29627
|
+
}).from(runs).innerJoin(querySnapshots, eq35(querySnapshots.runId, runs.id)).where(and28(
|
|
29628
|
+
eq35(runs.projectId, project.id),
|
|
29629
|
+
isNull(querySnapshots.queryId),
|
|
29630
|
+
isNull(querySnapshots.queryText)
|
|
29631
|
+
)).groupBy(runs.id).orderBy(runs.createdAt).all();
|
|
29632
|
+
const result = {
|
|
29633
|
+
project: project.name,
|
|
29634
|
+
examinedRuns: orphanRuns.length,
|
|
29635
|
+
orphanSnapshots: 0,
|
|
29636
|
+
recoveredByPosition: 0,
|
|
29637
|
+
recoveredByContent: 0,
|
|
29638
|
+
unrecovered: 0,
|
|
29639
|
+
dryRun: isDryRun,
|
|
29640
|
+
perRun: []
|
|
29641
|
+
};
|
|
29642
|
+
const updates = [];
|
|
29643
|
+
for (const run of orphanRuns) {
|
|
29644
|
+
const activeAt = activeQueriesAt(history, run.createdAt);
|
|
29645
|
+
const orphanSnaps = db.select({
|
|
29646
|
+
id: querySnapshots.id,
|
|
29647
|
+
provider: querySnapshots.provider,
|
|
29648
|
+
createdAt: querySnapshots.createdAt,
|
|
29649
|
+
answerText: querySnapshots.answerText
|
|
29650
|
+
}).from(querySnapshots).where(and28(
|
|
29651
|
+
eq35(querySnapshots.runId, run.runId),
|
|
29652
|
+
isNull(querySnapshots.queryId),
|
|
29653
|
+
isNull(querySnapshots.queryText)
|
|
29654
|
+
)).orderBy(querySnapshots.provider, querySnapshots.createdAt).all();
|
|
29655
|
+
const byProvider = /* @__PURE__ */ new Map();
|
|
29656
|
+
for (const s of orphanSnaps) {
|
|
29657
|
+
const arr = byProvider.get(s.provider);
|
|
29658
|
+
if (arr) arr.push(s);
|
|
29659
|
+
else byProvider.set(s.provider, [s]);
|
|
29660
|
+
}
|
|
29661
|
+
let runPosition = 0;
|
|
29662
|
+
let runContent = 0;
|
|
29663
|
+
let runUnrecovered = 0;
|
|
29664
|
+
for (const [, snaps] of byProvider) {
|
|
29665
|
+
if (snaps.length === activeAt.length) {
|
|
29666
|
+
for (let i = 0; i < snaps.length; i++) {
|
|
29667
|
+
updates.push({ id: snaps[i].id, queryText: activeAt[i] });
|
|
29668
|
+
runPosition++;
|
|
29669
|
+
}
|
|
29670
|
+
} else if (snaps.length < activeAt.length) {
|
|
29671
|
+
const LOOKAHEAD_LIMIT = 5;
|
|
29672
|
+
let cidx = 0;
|
|
29673
|
+
for (const snap of snaps) {
|
|
29674
|
+
const answerText = snap.answerText ?? "";
|
|
29675
|
+
let matchedIdx = -1;
|
|
29676
|
+
for (let i = cidx; i < Math.min(activeAt.length, cidx + LOOKAHEAD_LIMIT); i++) {
|
|
29677
|
+
if (contentMatchScore(activeAt[i], answerText) >= 1) {
|
|
29678
|
+
matchedIdx = i;
|
|
29679
|
+
break;
|
|
29680
|
+
}
|
|
29681
|
+
}
|
|
29682
|
+
if (matchedIdx >= 0) {
|
|
29683
|
+
updates.push({ id: snap.id, queryText: activeAt[matchedIdx] });
|
|
29684
|
+
runContent++;
|
|
29685
|
+
cidx = matchedIdx + 1;
|
|
29686
|
+
} else {
|
|
29687
|
+
runUnrecovered++;
|
|
29688
|
+
}
|
|
29689
|
+
}
|
|
29690
|
+
} else {
|
|
29691
|
+
runUnrecovered += snaps.length;
|
|
29692
|
+
}
|
|
29693
|
+
}
|
|
29694
|
+
result.orphanSnapshots += orphanSnaps.length;
|
|
29695
|
+
result.recoveredByPosition += runPosition;
|
|
29696
|
+
result.recoveredByContent += runContent;
|
|
29697
|
+
result.unrecovered += runUnrecovered;
|
|
29698
|
+
result.perRun.push({
|
|
29699
|
+
runId: run.runId,
|
|
29700
|
+
runCreatedAt: run.createdAt,
|
|
29701
|
+
activeQueryCount: activeAt.length,
|
|
29702
|
+
orphanSnaps: orphanSnaps.length,
|
|
29703
|
+
recoveredPosition: runPosition,
|
|
29704
|
+
recoveredContent: runContent,
|
|
29705
|
+
unrecovered: runUnrecovered
|
|
29706
|
+
});
|
|
29707
|
+
if (!isJson) {
|
|
29708
|
+
process.stderr.write(
|
|
29709
|
+
` ${run.createdAt} loc=${run.location ?? "-"} \u2192 ${orphanSnaps.length} orphan; ${runPosition} position-matched, ${runContent} content-matched, ${runUnrecovered} unrecovered
|
|
29710
|
+
`
|
|
29711
|
+
);
|
|
29712
|
+
}
|
|
29713
|
+
}
|
|
29714
|
+
if (!isDryRun && updates.length > 0) {
|
|
29715
|
+
db.transaction((tx) => {
|
|
29716
|
+
for (const u of updates) {
|
|
29717
|
+
tx.update(querySnapshots).set({ queryText: u.queryText }).where(eq35(querySnapshots.id, u.id)).run();
|
|
29718
|
+
}
|
|
29719
|
+
});
|
|
29720
|
+
}
|
|
29721
|
+
if (isJson) {
|
|
29722
|
+
console.log(JSON.stringify(result, null, 2));
|
|
29723
|
+
return;
|
|
29724
|
+
}
|
|
29725
|
+
console.log(`
|
|
29726
|
+
Snapshot attribution ${isDryRun ? "preview" : "recovery"} complete.`);
|
|
29727
|
+
console.log(` Examined runs: ${result.examinedRuns}`);
|
|
29728
|
+
console.log(` Orphan snapshots: ${result.orphanSnapshots}`);
|
|
29729
|
+
console.log(` Position-matched: ${result.recoveredByPosition}`);
|
|
29730
|
+
console.log(` Content-matched: ${result.recoveredByContent}`);
|
|
29731
|
+
console.log(` Unrecovered: ${result.unrecovered}`);
|
|
29732
|
+
if (isDryRun) {
|
|
29733
|
+
console.log(`
|
|
29734
|
+
No DB writes performed. Re-run without --dry-run to apply.`);
|
|
29735
|
+
}
|
|
29736
|
+
}
|
|
26973
29737
|
function reparseProviderSnapshot(provider, rawResponse) {
|
|
26974
29738
|
const envelope = parseJsonColumn(rawResponse, {});
|
|
26975
29739
|
const apiResponse = resolveStoredApiResponse(envelope);
|
|
@@ -27017,6 +29781,157 @@ function stringifyStoredSnapshotEnvelope(rawResponse, reparsed) {
|
|
|
27017
29781
|
...apiResponse ? { apiResponse } : {}
|
|
27018
29782
|
});
|
|
27019
29783
|
}
|
|
29784
|
+
async function backfillTrafficClassificationCommand(opts) {
|
|
29785
|
+
const config = loadConfig();
|
|
29786
|
+
const db = createClient(config.database);
|
|
29787
|
+
migrate(db);
|
|
29788
|
+
const projectFilter = opts?.project?.trim();
|
|
29789
|
+
const isDryRun = opts?.dryRun === true;
|
|
29790
|
+
const isJson = opts?.format === "json";
|
|
29791
|
+
const scopedProjects = projectFilter ? db.select().from(projects).where(eq35(projects.name, projectFilter)).all() : db.select().from(projects).all();
|
|
29792
|
+
if (scopedProjects.length === 0) {
|
|
29793
|
+
if (projectFilter && !isJson) {
|
|
29794
|
+
process.stderr.write(`No project named "${projectFilter}".
|
|
29795
|
+
`);
|
|
29796
|
+
}
|
|
29797
|
+
if (isJson) console.log(JSON.stringify({ project: projectFilter ?? null, examined: 0, reclassified: 0 }));
|
|
29798
|
+
return;
|
|
29799
|
+
}
|
|
29800
|
+
if (!isJson) {
|
|
29801
|
+
const mode = isDryRun ? " [DRY RUN \u2014 no writes]" : "";
|
|
29802
|
+
const scope = projectFilter ? `"${projectFilter}"` : "all projects";
|
|
29803
|
+
process.stderr.write(`Re-classifying unknown traffic samples for ${scope}${mode}...
|
|
29804
|
+
`);
|
|
29805
|
+
}
|
|
29806
|
+
const projectIds = scopedProjects.map((p) => p.id);
|
|
29807
|
+
const result = {
|
|
29808
|
+
project: projectFilter ?? null,
|
|
29809
|
+
examined: 0,
|
|
29810
|
+
reclassified: 0,
|
|
29811
|
+
unknownBefore: 0,
|
|
29812
|
+
unknownAfter: 0,
|
|
29813
|
+
dryRun: isDryRun,
|
|
29814
|
+
byBot: {}
|
|
29815
|
+
};
|
|
29816
|
+
const unknownCountRow = db.select({ n: sql15`count(*)` }).from(rawEventSamples).where(and28(
|
|
29817
|
+
eq35(rawEventSamples.eventType, "unknown"),
|
|
29818
|
+
inArray11(rawEventSamples.projectId, projectIds)
|
|
29819
|
+
)).get();
|
|
29820
|
+
result.unknownBefore = Number(unknownCountRow?.n ?? 0);
|
|
29821
|
+
const unknownSamples = db.select({
|
|
29822
|
+
id: rawEventSamples.id,
|
|
29823
|
+
projectId: rawEventSamples.projectId,
|
|
29824
|
+
sourceId: rawEventSamples.sourceId,
|
|
29825
|
+
ts: rawEventSamples.ts,
|
|
29826
|
+
userAgent: rawEventSamples.userAgent,
|
|
29827
|
+
pathNormalized: rawEventSamples.pathNormalized,
|
|
29828
|
+
status: rawEventSamples.status
|
|
29829
|
+
}).from(rawEventSamples).where(and28(
|
|
29830
|
+
eq35(rawEventSamples.eventType, "unknown"),
|
|
29831
|
+
inArray11(rawEventSamples.projectId, projectIds)
|
|
29832
|
+
)).all();
|
|
29833
|
+
result.examined = unknownSamples.length;
|
|
29834
|
+
if (unknownSamples.length === 0) {
|
|
29835
|
+
result.unknownAfter = result.unknownBefore;
|
|
29836
|
+
emitTrafficClassificationReport(result, isJson);
|
|
29837
|
+
return;
|
|
29838
|
+
}
|
|
29839
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
29840
|
+
for (const snap of unknownSamples) {
|
|
29841
|
+
if (!snap.userAgent) continue;
|
|
29842
|
+
const probe = {
|
|
29843
|
+
sourceType: TrafficSourceTypes["cloud-run"],
|
|
29844
|
+
evidenceKind: TrafficEvidenceKinds["raw-request"],
|
|
29845
|
+
confidence: TrafficEventConfidences.observed,
|
|
29846
|
+
eventId: snap.id,
|
|
29847
|
+
observedAt: snap.ts,
|
|
29848
|
+
method: "GET",
|
|
29849
|
+
requestUrl: `https://placeholder${snap.pathNormalized}`,
|
|
29850
|
+
host: "placeholder",
|
|
29851
|
+
path: snap.pathNormalized,
|
|
29852
|
+
queryString: null,
|
|
29853
|
+
status: snap.status ?? 200,
|
|
29854
|
+
userAgent: snap.userAgent,
|
|
29855
|
+
remoteIp: null,
|
|
29856
|
+
referer: null,
|
|
29857
|
+
latencyMs: null,
|
|
29858
|
+
requestSizeBytes: null,
|
|
29859
|
+
responseSizeBytes: null,
|
|
29860
|
+
providerResource: { type: "cloud_run_revision", labels: {} },
|
|
29861
|
+
providerLabels: {}
|
|
29862
|
+
};
|
|
29863
|
+
const classified = classifyCrawler(probe);
|
|
29864
|
+
if (!classified) continue;
|
|
29865
|
+
result.reclassified++;
|
|
29866
|
+
result.byBot[classified.botId] = (result.byBot[classified.botId] ?? 0) + 1;
|
|
29867
|
+
if (isDryRun) continue;
|
|
29868
|
+
db.update(rawEventSamples).set({ eventType: TrafficEventKinds.crawler }).where(eq35(rawEventSamples.id, snap.id)).run();
|
|
29869
|
+
const tsHour = new Date(snap.ts);
|
|
29870
|
+
tsHour.setUTCMinutes(0, 0, 0);
|
|
29871
|
+
db.insert(crawlerEventsHourly).values({
|
|
29872
|
+
projectId: snap.projectId,
|
|
29873
|
+
sourceId: snap.sourceId,
|
|
29874
|
+
tsHour: tsHour.toISOString(),
|
|
29875
|
+
botId: classified.botId,
|
|
29876
|
+
operator: classified.operator,
|
|
29877
|
+
verificationStatus: classified.verificationStatus,
|
|
29878
|
+
pathNormalized: snap.pathNormalized,
|
|
29879
|
+
status: snap.status ?? 200,
|
|
29880
|
+
hits: 1,
|
|
29881
|
+
sampledUserAgent: snap.userAgent,
|
|
29882
|
+
createdAt: now,
|
|
29883
|
+
updatedAt: now
|
|
29884
|
+
}).onConflictDoUpdate({
|
|
29885
|
+
target: [
|
|
29886
|
+
crawlerEventsHourly.projectId,
|
|
29887
|
+
crawlerEventsHourly.sourceId,
|
|
29888
|
+
crawlerEventsHourly.tsHour,
|
|
29889
|
+
crawlerEventsHourly.botId,
|
|
29890
|
+
crawlerEventsHourly.verificationStatus,
|
|
29891
|
+
crawlerEventsHourly.pathNormalized,
|
|
29892
|
+
crawlerEventsHourly.status
|
|
29893
|
+
],
|
|
29894
|
+
set: {
|
|
29895
|
+
hits: sql15`${crawlerEventsHourly.hits} + 1`,
|
|
29896
|
+
updatedAt: now
|
|
29897
|
+
}
|
|
29898
|
+
}).run();
|
|
29899
|
+
}
|
|
29900
|
+
if (!isDryRun) {
|
|
29901
|
+
const afterRow = db.select({ n: sql15`count(*)` }).from(rawEventSamples).where(and28(
|
|
29902
|
+
eq35(rawEventSamples.eventType, "unknown"),
|
|
29903
|
+
inArray11(rawEventSamples.projectId, projectIds)
|
|
29904
|
+
)).get();
|
|
29905
|
+
result.unknownAfter = Number(afterRow?.n ?? 0);
|
|
29906
|
+
} else {
|
|
29907
|
+
result.unknownAfter = result.unknownBefore - result.reclassified;
|
|
29908
|
+
}
|
|
29909
|
+
emitTrafficClassificationReport(result, isJson);
|
|
29910
|
+
}
|
|
29911
|
+
function emitTrafficClassificationReport(result, isJson) {
|
|
29912
|
+
if (isJson) {
|
|
29913
|
+
console.log(JSON.stringify(result, null, 2));
|
|
29914
|
+
return;
|
|
29915
|
+
}
|
|
29916
|
+
const verb = result.dryRun ? "Would re-classify" : "Re-classified";
|
|
29917
|
+
console.log(`
|
|
29918
|
+
Traffic classification ${result.dryRun ? "preview" : "recovery"} complete.`);
|
|
29919
|
+
console.log(` Examined unknowns: ${result.examined}`);
|
|
29920
|
+
console.log(` ${verb}: ${result.reclassified}`);
|
|
29921
|
+
console.log(` Unknown before: ${result.unknownBefore}`);
|
|
29922
|
+
console.log(` Unknown after: ${result.unknownAfter}`);
|
|
29923
|
+
if (result.reclassified > 0) {
|
|
29924
|
+
console.log(` By bot:`);
|
|
29925
|
+
const sorted = Object.entries(result.byBot).sort(([, a], [, b]) => b - a);
|
|
29926
|
+
for (const [bot, count] of sorted) {
|
|
29927
|
+
console.log(` ${count.toString().padStart(5)} ${bot}`);
|
|
29928
|
+
}
|
|
29929
|
+
}
|
|
29930
|
+
if (result.dryRun) {
|
|
29931
|
+
console.log(`
|
|
29932
|
+
No DB writes performed. Re-run without --dry-run to apply.`);
|
|
29933
|
+
}
|
|
29934
|
+
}
|
|
27020
29935
|
|
|
27021
29936
|
// src/provider-registry.ts
|
|
27022
29937
|
var ProviderRegistry = class {
|
|
@@ -27569,7 +30484,7 @@ import crypto34 from "crypto";
|
|
|
27569
30484
|
import { eq as eq40 } from "drizzle-orm";
|
|
27570
30485
|
|
|
27571
30486
|
// src/agent/session.ts
|
|
27572
|
-
import
|
|
30487
|
+
import fs14 from "fs";
|
|
27573
30488
|
import path14 from "path";
|
|
27574
30489
|
import { Agent } from "@mariozechner/pi-agent-core";
|
|
27575
30490
|
import { registerBuiltInApiProviders } from "@mariozechner/pi-ai";
|
|
@@ -27710,7 +30625,7 @@ function buildAgentProvidersResponse(config) {
|
|
|
27710
30625
|
}
|
|
27711
30626
|
|
|
27712
30627
|
// src/agent/skill-paths.ts
|
|
27713
|
-
import
|
|
30628
|
+
import fs12 from "fs";
|
|
27714
30629
|
import path12 from "path";
|
|
27715
30630
|
import { fileURLToPath } from "url";
|
|
27716
30631
|
function resolveAeroSkillDir(pkgDir) {
|
|
@@ -27721,14 +30636,14 @@ function resolveAeroSkillDir(pkgDir) {
|
|
|
27721
30636
|
path12.join(here, "../../../../skills/aero")
|
|
27722
30637
|
];
|
|
27723
30638
|
for (const candidate of candidates) {
|
|
27724
|
-
if (
|
|
30639
|
+
if (fs12.existsSync(path12.join(candidate, "SKILL.md"))) return candidate;
|
|
27725
30640
|
}
|
|
27726
30641
|
throw new Error(`Aero skill not found. Searched:
|
|
27727
30642
|
${candidates.join("\n ")}`);
|
|
27728
30643
|
}
|
|
27729
30644
|
|
|
27730
30645
|
// src/agent/skill-tools.ts
|
|
27731
|
-
import
|
|
30646
|
+
import fs13 from "fs";
|
|
27732
30647
|
import path13 from "path";
|
|
27733
30648
|
import { Type } from "@sinclair/typebox";
|
|
27734
30649
|
var MAX_DOC_CHARS = 2e4;
|
|
@@ -27751,12 +30666,12 @@ function parseDescription(body) {
|
|
|
27751
30666
|
}
|
|
27752
30667
|
function scanSkillDocs(skillDir) {
|
|
27753
30668
|
const refsDir = path13.join(skillDir ?? resolveAeroSkillDir(), "references");
|
|
27754
|
-
if (!
|
|
30669
|
+
if (!fs13.existsSync(refsDir)) return [];
|
|
27755
30670
|
const entries = [];
|
|
27756
|
-
for (const file of
|
|
30671
|
+
for (const file of fs13.readdirSync(refsDir)) {
|
|
27757
30672
|
if (!file.endsWith(".md")) continue;
|
|
27758
30673
|
const filePath = path13.join(refsDir, file);
|
|
27759
|
-
const body =
|
|
30674
|
+
const body = fs13.readFileSync(filePath, "utf-8");
|
|
27760
30675
|
entries.push({
|
|
27761
30676
|
slug: file.replace(/\.md$/, ""),
|
|
27762
30677
|
description: parseDescription(body),
|
|
@@ -27800,7 +30715,7 @@ function buildReadSkillDocTool() {
|
|
|
27800
30715
|
});
|
|
27801
30716
|
}
|
|
27802
30717
|
const filePath = path13.join(skillDir, "references", `${match.slug}.md`);
|
|
27803
|
-
const content =
|
|
30718
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
27804
30719
|
if (content.length > MAX_DOC_CHARS) {
|
|
27805
30720
|
return textResult({
|
|
27806
30721
|
slug: match.slug,
|
|
@@ -27894,10 +30809,10 @@ function ensureBuiltinsRegistered() {
|
|
|
27894
30809
|
}
|
|
27895
30810
|
function loadAeroSystemPrompt(pkgDir) {
|
|
27896
30811
|
const skillDir = resolveAeroSkillDir(pkgDir);
|
|
27897
|
-
const skillBody =
|
|
30812
|
+
const skillBody = fs14.readFileSync(path14.join(skillDir, "SKILL.md"), "utf-8");
|
|
27898
30813
|
const soulPath = path14.join(skillDir, "soul.md");
|
|
27899
|
-
if (!
|
|
27900
|
-
const soulBody =
|
|
30814
|
+
if (!fs14.existsSync(soulPath)) return skillBody;
|
|
30815
|
+
const soulBody = fs14.readFileSync(soulPath, "utf-8");
|
|
27901
30816
|
return `${soulBody.trimEnd()}
|
|
27902
30817
|
|
|
27903
30818
|
---
|
|
@@ -27955,7 +30870,7 @@ function resolveSessionProviderAndModel(config, opts) {
|
|
|
27955
30870
|
|
|
27956
30871
|
// src/agent/memory-store.ts
|
|
27957
30872
|
import crypto33 from "crypto";
|
|
27958
|
-
import { and as and31, desc as desc18, eq as eq39, like as like2, sql as
|
|
30873
|
+
import { and as and31, desc as desc18, eq as eq39, like as like2, sql as sql16 } from "drizzle-orm";
|
|
27959
30874
|
var COMPACTION_KEY_PREFIX = "compaction:";
|
|
27960
30875
|
var COMPACTION_NOTES_PER_SESSION = 3;
|
|
27961
30876
|
function rowToDto2(row) {
|
|
@@ -28041,7 +30956,7 @@ function writeCompactionNote(db, args) {
|
|
|
28041
30956
|
).orderBy(desc18(agentMemory.updatedAt)).all();
|
|
28042
30957
|
const stale = existing.slice(COMPACTION_NOTES_PER_SESSION).map((r) => r.id);
|
|
28043
30958
|
if (stale.length > 0) {
|
|
28044
|
-
tx.delete(agentMemory).where(
|
|
30959
|
+
tx.delete(agentMemory).where(sql16`${agentMemory.id} IN (${sql16.join(stale.map((s) => sql16`${s}`), sql16`, `)})`).run();
|
|
28045
30960
|
}
|
|
28046
30961
|
const row = tx.select().from(agentMemory).where(and31(eq39(agentMemory.projectId, args.projectId), eq39(agentMemory.key, key))).get();
|
|
28047
30962
|
if (row) inserted = rowToDto2(row);
|
|
@@ -29834,7 +32749,7 @@ async function createServer(opts) {
|
|
|
29834
32749
|
jobRunner.onRunCompleted = (runId, projectId) => runCoordinator.onRunCompleted(runId, projectId);
|
|
29835
32750
|
const snapshotService = new SnapshotService(registry);
|
|
29836
32751
|
const orphanedOpenClawDir = path15.join(os6.homedir(), ".openclaw-aero");
|
|
29837
|
-
if (
|
|
32752
|
+
if (fs15.existsSync(orphanedOpenClawDir)) {
|
|
29838
32753
|
app.log.warn(
|
|
29839
32754
|
{ path: orphanedOpenClawDir },
|
|
29840
32755
|
"OpenClaw gateway is no longer used. Remove ~/.openclaw-aero/ manually to reclaim the directory."
|
|
@@ -30181,6 +33096,24 @@ async function createServer(opts) {
|
|
|
30181
33096
|
sessionCookieName: SESSION_COOKIE_NAME,
|
|
30182
33097
|
resolveSessionApiKeyId,
|
|
30183
33098
|
explainContentRecommendation,
|
|
33099
|
+
// On-disk paths the daemon depends on. The api-routes plugin uses these
|
|
33100
|
+
// to fail loud (HTTP 503) when the operator wipes the DB or config out
|
|
33101
|
+
// from under a running serve — SQLite holds the inode open across
|
|
33102
|
+
// `unlink`, so without this the daemon keeps serving stale data from
|
|
33103
|
+
// an orphaned file and `rm ~/.canonry/data.db` silently does nothing.
|
|
33104
|
+
//
|
|
33105
|
+
// Only attach `configPath` if it actually exists at construction time:
|
|
33106
|
+
// production always boots via `serveCommand`, which calls `loadConfig()`
|
|
33107
|
+
// and would have thrown if the file were missing; tests that construct
|
|
33108
|
+
// `createServer` directly (bypassing `loadConfig`) won't have written
|
|
33109
|
+
// a config and shouldn't get 503s from a stub-missing file.
|
|
33110
|
+
runtimeStatePaths: (() => {
|
|
33111
|
+
const configPath = getConfigPath();
|
|
33112
|
+
return {
|
|
33113
|
+
databasePath: opts.config.database,
|
|
33114
|
+
configPath: fs15.existsSync(configPath) ? configPath : null
|
|
33115
|
+
};
|
|
33116
|
+
})(),
|
|
30184
33117
|
// Local canonry serve runs on the operator's machine, where pointing a
|
|
30185
33118
|
// webhook at localhost (Discord test container, Pipedream-mock dev server,
|
|
30186
33119
|
// etc.) is a legitimate workflow. Default to allowing it for the local
|
|
@@ -30553,7 +33486,7 @@ async function createServer(opts) {
|
|
|
30553
33486
|
});
|
|
30554
33487
|
const dirname = path15.dirname(fileURLToPath2(import.meta.url));
|
|
30555
33488
|
const assetsDir = path15.join(dirname, "..", "assets");
|
|
30556
|
-
if (
|
|
33489
|
+
if (fs15.existsSync(assetsDir)) {
|
|
30557
33490
|
const indexPath = path15.join(assetsDir, "index.html");
|
|
30558
33491
|
const injectConfig = (html) => {
|
|
30559
33492
|
const clientConfig = {};
|
|
@@ -30586,8 +33519,8 @@ async function createServer(opts) {
|
|
|
30586
33519
|
}
|
|
30587
33520
|
});
|
|
30588
33521
|
const serveIndex = (_request, reply) => {
|
|
30589
|
-
if (
|
|
30590
|
-
const html =
|
|
33522
|
+
if (fs15.existsSync(indexPath)) {
|
|
33523
|
+
const html = fs15.readFileSync(indexPath, "utf-8");
|
|
30591
33524
|
return reply.header("Cache-Control", "no-cache, must-revalidate").type("text/html").send(injectConfig(html));
|
|
30592
33525
|
}
|
|
30593
33526
|
return reply.status(404).send({ error: "Dashboard not built" });
|
|
@@ -30607,8 +33540,8 @@ async function createServer(opts) {
|
|
|
30607
33540
|
if (basePath && !url.startsWith(basePath)) {
|
|
30608
33541
|
return reply.status(404).send({ error: "Not found", path: request.url });
|
|
30609
33542
|
}
|
|
30610
|
-
if (
|
|
30611
|
-
const html =
|
|
33543
|
+
if (fs15.existsSync(indexPath)) {
|
|
33544
|
+
const html = fs15.readFileSync(indexPath, "utf-8");
|
|
30612
33545
|
return reply.header("Cache-Control", "no-cache, must-revalidate").type("text/html").send(injectConfig(html));
|
|
30613
33546
|
}
|
|
30614
33547
|
return reply.status(404).send({ error: "Not found" });
|
|
@@ -30696,6 +33629,8 @@ export {
|
|
|
30696
33629
|
backfillAiReferralPathsCommand,
|
|
30697
33630
|
backfillAnswerMentionsCommand,
|
|
30698
33631
|
backfillInsightsCommand,
|
|
33632
|
+
backfillSnapshotAttributionCommand,
|
|
33633
|
+
backfillTrafficClassificationCommand,
|
|
30699
33634
|
renderReportHtml,
|
|
30700
33635
|
setGoogleAuthConfig,
|
|
30701
33636
|
formatAuditFactorScore,
|