seo 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PRIVACY.md +11 -3
- package/dist/cli.js +78 -78
- package/dist/cli.js.map +1 -1
- package/dist/{dist-BvbFtizP.js → dist-BL_yf1fw.js} +1 -1
- package/dist/{dist-CsWo-wJG.js → dist-DqfdgVVU.js} +100 -100
- package/dist/dist-DqfdgVVU.js.map +1 -0
- package/dist/{esm-CM7xTOjT.js → esm-ZQwQYL0U.js} +2 -2
- package/dist/{esm-CM7xTOjT.js.map → esm-ZQwQYL0U.js.map} +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +193 -61
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +210 -65
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
- package/dist/dist-CsWo-wJG.js.map +0 -1
package/dist/mcp.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __seoCreateRequire } from 'node:module'; const require = __seoCreateRequire(import.meta.url);
|
|
2
|
-
import { i as __toESM, n as version, r as __commonJSMin, t as load } from "./esm-
|
|
2
|
+
import { i as __toESM, n as version, r as __commonJSMin, t as load } from "./esm-ZQwQYL0U.js";
|
|
3
3
|
import { createHash, randomUUID, sign } from "node:crypto";
|
|
4
4
|
import { ZodOptional, z } from "zod";
|
|
5
5
|
import { arch, homedir, platform, tmpdir, totalmem } from "node:os";
|
|
@@ -26,6 +26,7 @@ import { TextDecoder as TextDecoder$1, promisify } from "node:util";
|
|
|
26
26
|
import { execFile } from "node:child_process";
|
|
27
27
|
import "pino";
|
|
28
28
|
import "pino-pretty";
|
|
29
|
+
import { request } from "node:https";
|
|
29
30
|
import * as z3rt from "zod/v3";
|
|
30
31
|
import { ZodFirstPartyTypeKind } from "zod/v3";
|
|
31
32
|
import * as z4mini from "zod/v4-mini";
|
|
@@ -13877,7 +13878,7 @@ async function runAnalyticsReport(gfetch, propertyId, body, options) {
|
|
|
13877
13878
|
//#endregion
|
|
13878
13879
|
//#region packages/core/dist/bing/api.js
|
|
13879
13880
|
const BASE = "https://ssl.bing.com/webmaster/api.svc/json";
|
|
13880
|
-
const MAX_BYTES$
|
|
13881
|
+
const MAX_BYTES$3 = 8e6;
|
|
13881
13882
|
function bingCall(auth, options) {
|
|
13882
13883
|
return async (method, params = {}) => {
|
|
13883
13884
|
const url = new URL(`${BASE}/${method}`);
|
|
@@ -13902,7 +13903,7 @@ function bingCall(auth, options) {
|
|
|
13902
13903
|
if (response.status === 429 || /throttle/i.test(detail)) throw new SeoError("RATE_LIMITED", "Bing Webmaster is limiting requests. Try again in a few minutes.");
|
|
13903
13904
|
throw new SeoError("OPTIONAL_PROVIDER_UNAVAILABLE", `Bing Webmaster answered ${response.status}. ${detail}`.trim());
|
|
13904
13905
|
}
|
|
13905
|
-
return (await readJson(response, "Bing Webmaster", { maxBytes: MAX_BYTES$
|
|
13906
|
+
return (await readJson(response, "Bing Webmaster", { maxBytes: MAX_BYTES$3 })).d;
|
|
13906
13907
|
};
|
|
13907
13908
|
}
|
|
13908
13909
|
function day(value) {
|
|
@@ -16763,10 +16764,12 @@ function initDb(database, isNewDatabase) {
|
|
|
16763
16764
|
database.exec("DROP TABLE IF EXISTS provider_spend_notices");
|
|
16764
16765
|
ensureColumn(database, "http_cache", "metadata_json", "TEXT");
|
|
16765
16766
|
}).immediate();
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
|
|
16769
|
-
|
|
16767
|
+
try {
|
|
16768
|
+
runCacheMaintenance(database, {
|
|
16769
|
+
compact: true,
|
|
16770
|
+
allowFullVacuum: true
|
|
16771
|
+
});
|
|
16772
|
+
} catch {}
|
|
16770
16773
|
}
|
|
16771
16774
|
function getDb() {
|
|
16772
16775
|
if (db) return db;
|
|
@@ -16777,12 +16780,41 @@ function getDb() {
|
|
|
16777
16780
|
mode: 448
|
|
16778
16781
|
});
|
|
16779
16782
|
ensurePrivateDatabaseFiles(path);
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
|
|
16783
|
-
|
|
16783
|
+
const opened = new SqliteDatabase(path);
|
|
16784
|
+
try {
|
|
16785
|
+
ensurePrivateDatabaseFiles(path);
|
|
16786
|
+
initDb(opened, isNewDatabase);
|
|
16787
|
+
ensurePrivateDatabaseFiles(path);
|
|
16788
|
+
} catch (error) {
|
|
16789
|
+
opened.close();
|
|
16790
|
+
throw error;
|
|
16791
|
+
}
|
|
16792
|
+
db = opened;
|
|
16784
16793
|
return db;
|
|
16785
16794
|
}
|
|
16795
|
+
let memoryDb;
|
|
16796
|
+
function memoryCache() {
|
|
16797
|
+
if (!memoryDb) {
|
|
16798
|
+
memoryDb = new SqliteDatabase(":memory:");
|
|
16799
|
+
memoryDb.exec(CREATE_SQL);
|
|
16800
|
+
}
|
|
16801
|
+
return memoryDb;
|
|
16802
|
+
}
|
|
16803
|
+
function cacheDb() {
|
|
16804
|
+
if (memoryDb) return memoryDb;
|
|
16805
|
+
try {
|
|
16806
|
+
return getDb();
|
|
16807
|
+
} catch {
|
|
16808
|
+
return memoryCache();
|
|
16809
|
+
}
|
|
16810
|
+
}
|
|
16811
|
+
function writeToCache(write) {
|
|
16812
|
+
try {
|
|
16813
|
+
write(cacheDb());
|
|
16814
|
+
} catch {
|
|
16815
|
+
memoryCache();
|
|
16816
|
+
}
|
|
16817
|
+
}
|
|
16786
16818
|
function noteCacheWrite(sizeBytes = 0, database = getDb()) {
|
|
16787
16819
|
const counter = cacheMaintenanceCounters.get(database) ?? {
|
|
16788
16820
|
writes: 0,
|
|
@@ -16810,7 +16842,7 @@ function ga4RequestCanUseCache(body) {
|
|
|
16810
16842
|
}
|
|
16811
16843
|
async function runGa4Report(propertyId, body, opts = {}) {
|
|
16812
16844
|
const { client, identity } = await createGoogleAccessTokenClient(opts.accountEmail);
|
|
16813
|
-
const db =
|
|
16845
|
+
const db = cacheDb();
|
|
16814
16846
|
const queryHash = hashKey([
|
|
16815
16847
|
propertyId,
|
|
16816
16848
|
identity,
|
|
@@ -16823,10 +16855,12 @@ async function runGa4Report(propertyId, body, opts = {}) {
|
|
|
16823
16855
|
if (cacheable) {
|
|
16824
16856
|
const requestJson = JSON.stringify(body);
|
|
16825
16857
|
const responseJson = JSON.stringify(result);
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16858
|
+
writeToCache((database) => {
|
|
16859
|
+
database.prepare(`INSERT OR REPLACE INTO ga4_cache
|
|
16860
|
+
(property_id, query_hash, request_json, response_json, row_count, fetched_at, expires_at)
|
|
16861
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(propertyId, queryHash, requestJson, responseJson, result.rowCount ?? result.rows?.length ?? 0, Date.now(), Date.now() + 864e5);
|
|
16862
|
+
noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson), database);
|
|
16863
|
+
});
|
|
16830
16864
|
}
|
|
16831
16865
|
return result;
|
|
16832
16866
|
}
|
|
@@ -19198,7 +19232,7 @@ async function fetchRobotsSource(origin, refresh, options) {
|
|
|
19198
19232
|
const robotsUrl = new URL("/robots.txt", origin).toString();
|
|
19199
19233
|
const key = hashKey(["robots", robotsUrl]);
|
|
19200
19234
|
if (!refresh) {
|
|
19201
|
-
const cached =
|
|
19235
|
+
const cached = cacheDb().prepare("SELECT status, body_blob, expires_at FROM http_cache WHERE url_hash = ?").get(key);
|
|
19202
19236
|
if (cached?.body_blob && cached.status !== void 0 && cacheableStatus(cached.status) && cached.expires_at && cached.expires_at > Date.now()) return {
|
|
19203
19237
|
robotsUrl,
|
|
19204
19238
|
status: cached.status,
|
|
@@ -19217,12 +19251,12 @@ async function fetchRobotsSource(origin, refresh, options) {
|
|
|
19217
19251
|
signal: controller.signal
|
|
19218
19252
|
});
|
|
19219
19253
|
const text = await readBoundedResponseText(response, MAX_ROBOTS_RESPONSE_BYTES, "robots.txt response");
|
|
19220
|
-
if (options.writeCache !== false && cacheableStatus(response.status)) {
|
|
19221
|
-
|
|
19222
|
-
|
|
19223
|
-
|
|
19224
|
-
noteCacheWrite(Buffer.byteLength(text));
|
|
19225
|
-
}
|
|
19254
|
+
if (options.writeCache !== false && cacheableStatus(response.status)) writeToCache((database) => {
|
|
19255
|
+
database.prepare(`INSERT OR REPLACE INTO http_cache
|
|
19256
|
+
(url_hash, url, status, headers_json, body_blob, etag, fetched_at, expires_at)
|
|
19257
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(key, robotsUrl, response.status, "{}", Buffer.from(text), null, Date.now(), Date.now() + 864e5);
|
|
19258
|
+
noteCacheWrite(Buffer.byteLength(text), database);
|
|
19259
|
+
});
|
|
19226
19260
|
return {
|
|
19227
19261
|
robotsUrl,
|
|
19228
19262
|
status: response.status,
|
|
@@ -19329,7 +19363,6 @@ function decodePageFetchCacheEvidence(value) {
|
|
|
19329
19363
|
}
|
|
19330
19364
|
async function fetchPlain(url, refresh = false, timeoutMs = 2e4, rate, signal, respectRobots = false, writeCache = true) {
|
|
19331
19365
|
const startedAt = Date.now();
|
|
19332
|
-
const db = getDb();
|
|
19333
19366
|
const key = hashKey(["page", url]);
|
|
19334
19367
|
const host = new URL(url).host;
|
|
19335
19368
|
let robots = respectRobots ? await fetchRobots(new URL(url).origin, url, refresh, {
|
|
@@ -19337,7 +19370,7 @@ async function fetchPlain(url, refresh = false, timeoutMs = 2e4, rate, signal, r
|
|
|
19337
19370
|
signal
|
|
19338
19371
|
}) : void 0;
|
|
19339
19372
|
if (robots && robots.allowed !== true) throw new RobotsAccessError(robots.allowed === false ? "robots-disallowed" : "robots-deferred", robots);
|
|
19340
|
-
const cached =
|
|
19373
|
+
const cached = cacheDb().prepare("SELECT status, headers_json, body_blob, metadata_json, expires_at FROM http_cache WHERE url_hash = ? AND expires_at > ?").get(key, Date.now());
|
|
19341
19374
|
if (!refresh && cached) {
|
|
19342
19375
|
const evidence = decodePageFetchCacheEvidence(cached.metadata_json);
|
|
19343
19376
|
return {
|
|
@@ -19439,12 +19472,12 @@ async function fetchPlain(url, refresh = false, timeoutMs = 2e4, rate, signal, r
|
|
|
19439
19472
|
warnings: [...robots.allowed === null ? [`robots.txt availability is unknown${robots.status ? ` after HTTP ${robots.status}` : ""}; this fetch does not prove crawler access is allowed.`] : [], ...accessBlock ? [`${accessBlock.guidance.summary} Identify the crawler as ${accessBlock.crawler.userAgent}.`] : []],
|
|
19440
19473
|
robotsTxt: pageRobotsEvidence(robots)
|
|
19441
19474
|
};
|
|
19442
|
-
if (!accessBlock && writeCache) {
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
noteCacheWrite(Buffer.byteLength(html));
|
|
19447
|
-
}
|
|
19475
|
+
if (!accessBlock && writeCache) writeToCache((database) => {
|
|
19476
|
+
database.prepare(`INSERT OR REPLACE INTO http_cache
|
|
19477
|
+
(url_hash, url, status, headers_json, body_blob, metadata_json, etag, fetched_at, expires_at)
|
|
19478
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(key, url, response.response.status, JSON.stringify(headerMap), Buffer.from(html), encodePageFetchCacheEvidence(result), response.response.headers.get("etag"), Date.now(), Date.now() + 36e5);
|
|
19479
|
+
noteCacheWrite(Buffer.byteLength(html), database);
|
|
19480
|
+
});
|
|
19448
19481
|
return result;
|
|
19449
19482
|
}
|
|
19450
19483
|
//#endregion
|
|
@@ -20302,7 +20335,7 @@ function resolveSearchDateWindow(input = 28) {
|
|
|
20302
20335
|
}
|
|
20303
20336
|
async function querySearchAnalytics(site, body, opts = {}) {
|
|
20304
20337
|
const { client, identity } = await getAuthorized(opts.accountEmail ?? await cloudAccountFor(site));
|
|
20305
|
-
const db =
|
|
20338
|
+
const db = cacheDb();
|
|
20306
20339
|
const queryHash = hashKey([
|
|
20307
20340
|
site,
|
|
20308
20341
|
identity,
|
|
@@ -20322,10 +20355,12 @@ async function querySearchAnalytics(site, body, opts = {}) {
|
|
|
20322
20355
|
const calls = result.calls;
|
|
20323
20356
|
const requestJson = JSON.stringify(body);
|
|
20324
20357
|
const responseJson = JSON.stringify(allRows);
|
|
20325
|
-
|
|
20326
|
-
|
|
20327
|
-
|
|
20328
|
-
|
|
20358
|
+
writeToCache((database) => {
|
|
20359
|
+
database.prepare(`INSERT OR REPLACE INTO gsc_cache
|
|
20360
|
+
(site_url, query_hash, request_json, response_json, row_count, fetched_at, expires_at)
|
|
20361
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(site, queryHash, requestJson, responseJson, allRows.length, Date.now(), Date.now() + 864e5);
|
|
20362
|
+
noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson), database);
|
|
20363
|
+
});
|
|
20329
20364
|
return {
|
|
20330
20365
|
rows: allRows,
|
|
20331
20366
|
calls,
|
|
@@ -20461,8 +20496,10 @@ async function queryPagesTopQueriesBatch(site, pageUrls, range = 28) {
|
|
|
20461
20496
|
//#region packages/core/dist/gsc/client/sites.js
|
|
20462
20497
|
async function listSites(_refresh = false, accountEmail) {
|
|
20463
20498
|
const entries = !accountEmail && cloudLinked() ? await allCloudSites() : await listSearchConsoleSites(googleFetchFor((await getAuthorized(accountEmail)).client), LOCAL_SIGN_IN);
|
|
20464
|
-
|
|
20465
|
-
|
|
20499
|
+
writeToCache((database) => {
|
|
20500
|
+
const insert = database.prepare("INSERT OR REPLACE INTO sites (site_url, display_name, permission, added_at, is_default) VALUES (?, ?, ?, ?, COALESCE((SELECT is_default FROM sites WHERE site_url = ?), 0))");
|
|
20501
|
+
for (const site of entries) insert.run(site.siteUrl, site.siteUrl, site.permissionLevel ?? null, Date.now(), site.siteUrl);
|
|
20502
|
+
});
|
|
20466
20503
|
return entries;
|
|
20467
20504
|
}
|
|
20468
20505
|
async function allCloudSites() {
|
|
@@ -26587,7 +26624,7 @@ function taskIds(value) {
|
|
|
26587
26624
|
}
|
|
26588
26625
|
}
|
|
26589
26626
|
function readProviderCache(key, schema, options = {}) {
|
|
26590
|
-
const database = options.database ??
|
|
26627
|
+
const database = options.database ?? cacheDb();
|
|
26591
26628
|
const now = options.now ?? Date.now();
|
|
26592
26629
|
const hash = requestHash(key, stableProviderRequestJson(key.request));
|
|
26593
26630
|
const row = database.prepare(`SELECT response_json, row_count, source_cost_micros, task_ids_json,
|
|
@@ -26608,9 +26645,11 @@ function readProviderCache(key, schema, options = {}) {
|
|
|
26608
26645
|
taskIds: taskIds(row.task_ids_json)
|
|
26609
26646
|
};
|
|
26610
26647
|
} catch {
|
|
26611
|
-
|
|
26612
|
-
|
|
26613
|
-
AND
|
|
26648
|
+
try {
|
|
26649
|
+
database.prepare(`DELETE FROM provider_cache
|
|
26650
|
+
WHERE provider = ? AND credential_scope = ? AND operation = ?
|
|
26651
|
+
AND request_hash = ?`).run(key.provider, key.credentialScope, key.operation, hash);
|
|
26652
|
+
} catch {}
|
|
26614
26653
|
return null;
|
|
26615
26654
|
}
|
|
26616
26655
|
}
|
|
@@ -26621,19 +26660,22 @@ function writeProviderCache(key, input, options = {}) {
|
|
|
26621
26660
|
code: "configuration",
|
|
26622
26661
|
message: `Provider cache TTL must be between 1 and ${CACHE_MAX_AGE_MS} milliseconds.`
|
|
26623
26662
|
});
|
|
26624
|
-
const database = options.database ?? getDb();
|
|
26625
26663
|
const now = options.now ?? Date.now();
|
|
26626
26664
|
const expiresAt = now + input.ttlMs;
|
|
26627
26665
|
const requestJson = stableProviderRequestJson(key.request);
|
|
26628
26666
|
const responseJson = JSON.stringify(input.data);
|
|
26629
26667
|
const normalizedTaskIds = [...new Set(input.taskIds)].filter((id) => id.length > 0 && id.length <= 100).sort((left, right) => left < right ? -1 : left > right ? 1 : 0).slice(0, 20);
|
|
26630
26668
|
const taskIdsJson = JSON.stringify(normalizedTaskIds);
|
|
26631
|
-
|
|
26632
|
-
|
|
26633
|
-
|
|
26634
|
-
|
|
26635
|
-
|
|
26636
|
-
|
|
26669
|
+
const save = (database) => {
|
|
26670
|
+
database.prepare(`INSERT OR REPLACE INTO provider_cache (
|
|
26671
|
+
provider, credential_scope, operation, request_hash, request_json,
|
|
26672
|
+
response_json, row_count, source_cost_micros, task_ids_json,
|
|
26673
|
+
fetched_at, expires_at
|
|
26674
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(key.provider, key.credentialScope, key.operation, requestHash(key, requestJson), requestJson, responseJson, input.rowCount, input.sourceCostMicros, taskIdsJson, now, expiresAt);
|
|
26675
|
+
noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson) + Buffer.byteLength(taskIdsJson), database);
|
|
26676
|
+
};
|
|
26677
|
+
if (options.database) save(options.database);
|
|
26678
|
+
else writeToCache(save);
|
|
26637
26679
|
return {
|
|
26638
26680
|
data: input.data,
|
|
26639
26681
|
storedAt: new Date(now).toISOString(),
|
|
@@ -27256,7 +27298,7 @@ async function loadInstalledProviderExtensions(options = {}) {
|
|
|
27256
27298
|
const DEFAULT_MAX_REQUESTS = 8;
|
|
27257
27299
|
const MAX_RESPONSE_BYTES$1 = 10 * 1024 * 1024;
|
|
27258
27300
|
const MAX_REQUEST_BODY_BYTES = 64 * 1024;
|
|
27259
|
-
const TIMEOUT_MS$
|
|
27301
|
+
const TIMEOUT_MS$2 = 15e3;
|
|
27260
27302
|
function normalizeProviderExtensionAccount(provider, account) {
|
|
27261
27303
|
const fields = provider.connection.fields.filter((field) => field.kind === "account");
|
|
27262
27304
|
const allowed = new Set(fields.map((field) => field.id));
|
|
@@ -27303,7 +27345,7 @@ function runtimeForProvider(provider, options = {}) {
|
|
|
27303
27345
|
},
|
|
27304
27346
|
fetch: providerFetch,
|
|
27305
27347
|
maxResponseBytes: MAX_RESPONSE_BYTES$1,
|
|
27306
|
-
timeoutMs: TIMEOUT_MS$
|
|
27348
|
+
timeoutMs: TIMEOUT_MS$2,
|
|
27307
27349
|
retry: (input.method ?? "GET") === "GET" ? "safe" : "never",
|
|
27308
27350
|
schema: z.unknown()
|
|
27309
27351
|
});
|
|
@@ -36851,7 +36893,7 @@ function reportId$1(input) {
|
|
|
36851
36893
|
})).digest("hex").slice(0, 20)}`;
|
|
36852
36894
|
}
|
|
36853
36895
|
function cacheGet(id, now) {
|
|
36854
|
-
const row =
|
|
36896
|
+
const row = cacheDb().prepare("SELECT report_json FROM performance_reports WHERE id = ? AND expires_at > ?").get(id, now);
|
|
36855
36897
|
if (!row?.report_json) return void 0;
|
|
36856
36898
|
try {
|
|
36857
36899
|
const report = JSON.parse(row.report_json);
|
|
@@ -36866,10 +36908,12 @@ function cacheSet(report, now) {
|
|
|
36866
36908
|
raw: void 0
|
|
36867
36909
|
};
|
|
36868
36910
|
const reportJson = JSON.stringify(stored);
|
|
36869
|
-
|
|
36870
|
-
|
|
36871
|
-
|
|
36872
|
-
|
|
36911
|
+
writeToCache((database) => {
|
|
36912
|
+
database.prepare(`INSERT OR REPLACE INTO performance_reports
|
|
36913
|
+
(id, url, strategy, report_json, created_at, expires_at)
|
|
36914
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(report.id, report.url, report.strategy, reportJson, Date.parse(report.generatedAt), now + CACHE_TTL_MS);
|
|
36915
|
+
noteCacheWrite(Buffer.byteLength(reportJson), database);
|
|
36916
|
+
});
|
|
36873
36917
|
}
|
|
36874
36918
|
async function fallbackReport(input) {
|
|
36875
36919
|
const fetched = await fetchPage(input.url, {
|
|
@@ -39053,7 +39097,7 @@ async function updatePostmortemWorkflow(input, dependencies = {}) {
|
|
|
39053
39097
|
//#endregion
|
|
39054
39098
|
//#region packages/core/dist/clicky/api.js
|
|
39055
39099
|
const ENDPOINT$1 = "https://api.clicky.com/api/stats/4";
|
|
39056
|
-
const MAX_BYTES$
|
|
39100
|
+
const MAX_BYTES$2 = 5e6;
|
|
39057
39101
|
var ClickyError = class extends Error {
|
|
39058
39102
|
code;
|
|
39059
39103
|
constructor(code, message) {
|
|
@@ -39080,7 +39124,7 @@ async function clickyStats(site, types, options = {}) {
|
|
|
39080
39124
|
throw new ClickyError("remote", "Could not reach Clicky. Try again.");
|
|
39081
39125
|
});
|
|
39082
39126
|
if (!response.ok) throw new ClickyError("remote", `Clicky returned ${response.status}.`);
|
|
39083
|
-
const groups = await readJson(response, "Clicky", { maxBytes: MAX_BYTES$
|
|
39127
|
+
const groups = await readJson(response, "Clicky", { maxBytes: MAX_BYTES$2 });
|
|
39084
39128
|
if (!Array.isArray(groups)) throw new ClickyError("remote", "Clicky returned invalid data.");
|
|
39085
39129
|
const failed = groups.find((group) => typeof group?.error === "string");
|
|
39086
39130
|
if (failed?.error) throw /sitekey|site id|authenticat|permission/iu.test(failed.error) ? new ClickyError("auth", `Clicky rejected site ID ${site.siteId} or its sitekey.`) : new ClickyError("remote", `Clicky: ${failed.error.slice(0, 200)}`);
|
|
@@ -40897,8 +40941,8 @@ function internalLinksText(report, options) {
|
|
|
40897
40941
|
//#endregion
|
|
40898
40942
|
//#region packages/core/dist/commands/page-facts.js
|
|
40899
40943
|
const MAX_PAGES = 20;
|
|
40900
|
-
const TIMEOUT_MS = 6e3;
|
|
40901
|
-
const MAX_BYTES = 1e6;
|
|
40944
|
+
const TIMEOUT_MS$1 = 6e3;
|
|
40945
|
+
const MAX_BYTES$1 = 1e6;
|
|
40902
40946
|
const clean = (value) => value?.trim().replace(/\s+/g, " ") || null;
|
|
40903
40947
|
async function boundedText(response) {
|
|
40904
40948
|
if (!response.body) return "";
|
|
@@ -40906,7 +40950,7 @@ async function boundedText(response) {
|
|
|
40906
40950
|
const decoder = new TextDecoder();
|
|
40907
40951
|
let text = "";
|
|
40908
40952
|
let total = 0;
|
|
40909
|
-
while (total < MAX_BYTES) {
|
|
40953
|
+
while (total < MAX_BYTES$1) {
|
|
40910
40954
|
const { done, value } = await reader.read();
|
|
40911
40955
|
if (done) return text + decoder.decode();
|
|
40912
40956
|
total += value.byteLength;
|
|
@@ -40986,7 +41030,7 @@ async function facts(url) {
|
|
|
40986
41030
|
"user-agent": SEO_CRAWLER_USER_AGENT,
|
|
40987
41031
|
accept: "text/html"
|
|
40988
41032
|
},
|
|
40989
|
-
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
41033
|
+
signal: AbortSignal.timeout(TIMEOUT_MS$1)
|
|
40990
41034
|
});
|
|
40991
41035
|
out.status = response.status;
|
|
40992
41036
|
const location = response.headers.get("location");
|
|
@@ -42759,6 +42803,94 @@ var LocalCredentialsProvider = class {
|
|
|
42759
42803
|
};
|
|
42760
42804
|
new LocalCredentialsProvider();
|
|
42761
42805
|
//#endregion
|
|
42806
|
+
//#region packages/core/dist/update-notice.js
|
|
42807
|
+
const REGISTRY_URL = "https://registry.npmjs.org/seo/latest";
|
|
42808
|
+
const CHECK_EVERY_MS = 864e5;
|
|
42809
|
+
const TIMEOUT_MS = 2e3;
|
|
42810
|
+
const MAX_BYTES = 65536;
|
|
42811
|
+
let checking = false;
|
|
42812
|
+
function runByNpx(env, cliPath) {
|
|
42813
|
+
if (env.npm_command === "exec" || /npx/i.test(env.npm_execpath ?? "")) return true;
|
|
42814
|
+
if (!cliPath) return false;
|
|
42815
|
+
let path = cliPath;
|
|
42816
|
+
try {
|
|
42817
|
+
path = realpathSync(cliPath);
|
|
42818
|
+
} catch {}
|
|
42819
|
+
return /[\\/](?:_npx|dlx)[\\/]/.test(path);
|
|
42820
|
+
}
|
|
42821
|
+
function isNewerVersion(current, latest) {
|
|
42822
|
+
const parse = (value) => value.replace(/^v/, "").split("-")[0]?.split(".").map((part) => Number.parseInt(part, 10)) ?? [];
|
|
42823
|
+
const currentParts = parse(current);
|
|
42824
|
+
const latestParts = parse(latest);
|
|
42825
|
+
for (let index = 0; index < 3; index += 1) {
|
|
42826
|
+
const currentPart = currentParts[index] ?? 0;
|
|
42827
|
+
const latestPart = latestParts[index] ?? 0;
|
|
42828
|
+
if (!Number.isFinite(currentPart) || !Number.isFinite(latestPart)) return false;
|
|
42829
|
+
if (latestPart > currentPart) return true;
|
|
42830
|
+
if (latestPart < currentPart) return false;
|
|
42831
|
+
}
|
|
42832
|
+
return false;
|
|
42833
|
+
}
|
|
42834
|
+
function isLatestCache(value) {
|
|
42835
|
+
if (!value || typeof value !== "object") return false;
|
|
42836
|
+
const cache = value;
|
|
42837
|
+
return typeof cache.checkedAt === "number" && typeof cache.latest === "string" && /^\d+\.\d+\.\d+$/.test(cache.latest);
|
|
42838
|
+
}
|
|
42839
|
+
function checkRegistry(cacheFile, now) {
|
|
42840
|
+
if (checking) return;
|
|
42841
|
+
checking = true;
|
|
42842
|
+
const done = () => {
|
|
42843
|
+
checking = false;
|
|
42844
|
+
};
|
|
42845
|
+
const req = request(REGISTRY_URL, { headers: { accept: "application/json" } });
|
|
42846
|
+
const timer = setTimeout(() => req.destroy(), TIMEOUT_MS);
|
|
42847
|
+
timer.unref();
|
|
42848
|
+
req.on("socket", (socket) => socket.unref());
|
|
42849
|
+
req.on("error", () => void 0);
|
|
42850
|
+
req.on("close", () => {
|
|
42851
|
+
clearTimeout(timer);
|
|
42852
|
+
done();
|
|
42853
|
+
});
|
|
42854
|
+
req.on("response", (response) => {
|
|
42855
|
+
const chunks = [];
|
|
42856
|
+
let size = 0;
|
|
42857
|
+
response.on("error", () => void 0);
|
|
42858
|
+
response.on("data", (chunk) => {
|
|
42859
|
+
size += chunk.length;
|
|
42860
|
+
if (size > MAX_BYTES) req.destroy();
|
|
42861
|
+
else chunks.push(chunk);
|
|
42862
|
+
});
|
|
42863
|
+
response.on("end", () => {
|
|
42864
|
+
if (response.statusCode !== 200 || size > MAX_BYTES) return;
|
|
42865
|
+
readJson(new Response(Buffer.concat(chunks)), "The npm registry").then((body) => {
|
|
42866
|
+
const cache = {
|
|
42867
|
+
checkedAt: now,
|
|
42868
|
+
latest: body.version
|
|
42869
|
+
};
|
|
42870
|
+
if (isLatestCache(cache)) writeJsonAtomic(cacheFile, cache, 384);
|
|
42871
|
+
}).catch(() => void 0);
|
|
42872
|
+
});
|
|
42873
|
+
});
|
|
42874
|
+
req.end();
|
|
42875
|
+
}
|
|
42876
|
+
function updateNotice(options = {}) {
|
|
42877
|
+
try {
|
|
42878
|
+
const env = options.env ?? process.env;
|
|
42879
|
+
const argv = options.argv ?? process.argv;
|
|
42880
|
+
if (env.NO_UPDATE_NOTIFIER || argv.includes("--no-update-notifier") || isTelemetryCi(env)) return;
|
|
42881
|
+
const cacheFile = options.cacheFile ?? join(getSeoCliPaths().cacheDir, "latest-version.json");
|
|
42882
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
42883
|
+
const stored = readJsonFile(cacheFile);
|
|
42884
|
+
const cache = isLatestCache(stored) ? stored : void 0;
|
|
42885
|
+
if (!cache || now - cache.checkedAt >= CHECK_EVERY_MS) checkRegistry(cacheFile, now);
|
|
42886
|
+
const current = options.version ?? SEO_VERSION;
|
|
42887
|
+
if (!cache || !isNewerVersion(current, cache.latest)) return void 0;
|
|
42888
|
+
return runByNpx(env, options.cliPath ?? argv[1]) ? `seo ${cache.latest} is out (you have ${current}). Run npx -y seo@latest; in an MCP config use seo@latest, then restart the client.` : `seo ${cache.latest} is out (you have ${current}). Update with: npm i -g seo`;
|
|
42889
|
+
} catch {
|
|
42890
|
+
return;
|
|
42891
|
+
}
|
|
42892
|
+
}
|
|
42893
|
+
//#endregion
|
|
42762
42894
|
//#region packages/mcp/src/agent-output-budget.ts
|
|
42763
42895
|
const AGENT_STRUCTURED_OUTPUT_MAX_BYTES = 96 * 1024;
|
|
42764
42896
|
function jsonBytes(value) {
|
|
@@ -45305,7 +45437,7 @@ function text(value) {
|
|
|
45305
45437
|
text: value
|
|
45306
45438
|
}] };
|
|
45307
45439
|
}
|
|
45308
|
-
async function
|
|
45440
|
+
async function countedRun(command, args, telemetry, run) {
|
|
45309
45441
|
const report = telemetry ? telemetryReportFor(command, {
|
|
45310
45442
|
section: typeof args.section === "string" ? args.section : void 0,
|
|
45311
45443
|
action: typeof args.action === "string" ? args.action : void 0
|
|
@@ -45317,10 +45449,22 @@ async function counted(command, args, telemetry, run) {
|
|
|
45317
45449
|
else trackTelemetryReportComplete(report, telemetry());
|
|
45318
45450
|
return result;
|
|
45319
45451
|
} catch (error) {
|
|
45320
|
-
|
|
45321
|
-
|
|
45452
|
+
const failure = localError(error);
|
|
45453
|
+
if (report && telemetry) trackTelemetryReportFailed(report, failure, telemetry());
|
|
45454
|
+
return toolError(failure);
|
|
45322
45455
|
}
|
|
45323
45456
|
}
|
|
45457
|
+
async function counted(command, args, telemetry, run) {
|
|
45458
|
+
const result = await countedRun(command, args, telemetry, run);
|
|
45459
|
+
const notice = updateNotice();
|
|
45460
|
+
return notice ? {
|
|
45461
|
+
...result,
|
|
45462
|
+
content: [...result.content, {
|
|
45463
|
+
type: "text",
|
|
45464
|
+
text: notice
|
|
45465
|
+
}]
|
|
45466
|
+
} : result;
|
|
45467
|
+
}
|
|
45324
45468
|
function registerSharedTools(server, options = {}) {
|
|
45325
45469
|
const surface = {
|
|
45326
45470
|
deps: nodeCommandDeps({ call: mcpCall }),
|
|
@@ -45433,6 +45577,7 @@ async function startMcpServer(opts = {}) {
|
|
|
45433
45577
|
}
|
|
45434
45578
|
const transport = new StdioServerTransport();
|
|
45435
45579
|
await server.connect(transport);
|
|
45580
|
+
updateNotice();
|
|
45436
45581
|
}
|
|
45437
45582
|
//#endregion
|
|
45438
45583
|
export { AGENT_STRUCTURED_OUTPUT_MAX_BYTES, REPORT_CATEGORIES, compactAgentWorkflowOutput, createServer, describeReport, executeReport, listReports, runReport, startMcpServer };
|