@siteoshq/cli 2.0.0 → 2.2.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/README.md +22 -4
- package/dist/cli.js +348 -200
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7840,11 +7840,15 @@ var filters = [
|
|
|
7840
7840
|
"cursor"
|
|
7841
7841
|
];
|
|
7842
7842
|
var TRACE_EXPLORER_FLAGS = {
|
|
7843
|
+
coverage: ["environment"],
|
|
7844
|
+
"gtm summary": ["environment", "period"],
|
|
7845
|
+
"notifications show": ["environment"],
|
|
7846
|
+
"notifications destinations": ["environment", "cursor"],
|
|
7843
7847
|
destinations: filters,
|
|
7844
7848
|
events: filters,
|
|
7845
7849
|
properties: filters,
|
|
7846
|
-
issues: filters,
|
|
7847
|
-
observations: filters,
|
|
7850
|
+
issues: [...filters, "container-id", "tag-id"],
|
|
7851
|
+
observations: [...filters, "container-id", "tag-id", "result"],
|
|
7848
7852
|
"issue show": ["environment", "id", "cursor"],
|
|
7849
7853
|
"observation show": ["environment", "batch-id", "event-id"]
|
|
7850
7854
|
};
|
|
@@ -7860,6 +7864,21 @@ var FilterValues = z11.object({
|
|
|
7860
7864
|
event: z11.string().min(1).max(160).optional(),
|
|
7861
7865
|
property: z11.string().min(1).max(160).optional(),
|
|
7862
7866
|
"page-view": z11.string().uuid().optional(),
|
|
7867
|
+
"container-id": z11.string().regex(/^GTM-[A-Z0-9]{4,20}$/u).optional(),
|
|
7868
|
+
"tag-id": z11.string().regex(/^[0-9]{1,20}$/u).optional(),
|
|
7869
|
+
result: z11.enum([
|
|
7870
|
+
"success",
|
|
7871
|
+
"failure",
|
|
7872
|
+
"exception",
|
|
7873
|
+
"timeout",
|
|
7874
|
+
"initiated",
|
|
7875
|
+
"completed_2xx",
|
|
7876
|
+
"completed_4xx",
|
|
7877
|
+
"completed_5xx",
|
|
7878
|
+
"network_error",
|
|
7879
|
+
"beacon_accepted",
|
|
7880
|
+
"result_unknown"
|
|
7881
|
+
]).optional(),
|
|
7863
7882
|
search: z11.string().max(160).optional(),
|
|
7864
7883
|
state: z11.enum([
|
|
7865
7884
|
"all",
|
|
@@ -7873,6 +7892,7 @@ var FilterValues = z11.object({
|
|
|
7873
7892
|
]).optional(),
|
|
7874
7893
|
rule: z11.string().min(1).max(80).optional(),
|
|
7875
7894
|
kind: z11.enum([
|
|
7895
|
+
"tag_execution",
|
|
7876
7896
|
"data_layer",
|
|
7877
7897
|
"fetch",
|
|
7878
7898
|
"xhr",
|
|
@@ -7891,18 +7911,22 @@ function traceExplorerSuffix(route, values) {
|
|
|
7891
7911
|
if (route === "issue show" || route === "observation show") {
|
|
7892
7912
|
const keys = route === "issue show" ? ["id"] : ["batch-id", "event-id"];
|
|
7893
7913
|
for (const key of keys) {
|
|
7894
|
-
|
|
7914
|
+
const value = values[key];
|
|
7915
|
+
const plain = key === "id" && typeof value === "string" ? value.replace(/^trc_incident_/u, "") : value;
|
|
7916
|
+
if (!z11.string().uuid().safeParse(plain).success)
|
|
7895
7917
|
throw new Error(`Use --${key} with the UUID returned by Trace.`);
|
|
7896
7918
|
}
|
|
7897
7919
|
if (values.cursor !== void 0) {
|
|
7898
|
-
if (!z11.string().uuid().safeParse(
|
|
7920
|
+
if (!z11.string().uuid().safeParse(
|
|
7921
|
+
typeof values.cursor === "string" ? values.cursor.replace(/^trc_finding_/u, "") : values.cursor
|
|
7922
|
+
).success)
|
|
7899
7923
|
throw new Error(
|
|
7900
7924
|
"Use --cursor with the nextCursor returned by this issue."
|
|
7901
7925
|
);
|
|
7902
7926
|
query.set("cursor", values.cursor);
|
|
7903
7927
|
}
|
|
7904
|
-
const
|
|
7905
|
-
return `${
|
|
7928
|
+
const suffix2 = route === "issue show" ? `/issues/${encodeURIComponent(values.id)}` : `/observations/${encodeURIComponent(values["batch-id"])}/${encodeURIComponent(values["event-id"])}`;
|
|
7929
|
+
return `${suffix2}${query.size ? `?${query}` : ""}`;
|
|
7906
7930
|
}
|
|
7907
7931
|
const parsed = FilterValues.safeParse(values);
|
|
7908
7932
|
if (!parsed.success) {
|
|
@@ -7913,9 +7937,21 @@ function traceExplorerSuffix(route, values) {
|
|
|
7913
7937
|
}
|
|
7914
7938
|
for (const [key, value] of Object.entries(parsed.data)) {
|
|
7915
7939
|
if (value !== void 0)
|
|
7916
|
-
query.set(
|
|
7940
|
+
query.set(
|
|
7941
|
+
{
|
|
7942
|
+
"page-view": "pageView",
|
|
7943
|
+
"container-id": "containerId",
|
|
7944
|
+
"tag-id": "tagId"
|
|
7945
|
+
}[key] ?? key,
|
|
7946
|
+
value
|
|
7947
|
+
);
|
|
7917
7948
|
}
|
|
7918
|
-
|
|
7949
|
+
const suffix = {
|
|
7950
|
+
"gtm summary": "gtm/summary",
|
|
7951
|
+
"notifications show": "notifications",
|
|
7952
|
+
"notifications destinations": "notification-destinations"
|
|
7953
|
+
}[route] ?? route;
|
|
7954
|
+
return `/${suffix}${query.size ? `?${query}` : ""}`;
|
|
7919
7955
|
}
|
|
7920
7956
|
function tracePublicationVersion(value) {
|
|
7921
7957
|
if (value === void 0) return void 0;
|
|
@@ -7956,11 +7992,18 @@ Usage:
|
|
|
7956
7992
|
siteos trace status [--json]
|
|
7957
7993
|
siteos trace environments [--json]
|
|
7958
7994
|
siteos trace report [--environment <slug>] [--json]
|
|
7995
|
+
siteos trace coverage [--environment <slug>] [--json]
|
|
7996
|
+
siteos trace gtm summary [--environment <slug>] [--period <24h|7d>] [--json]
|
|
7997
|
+
siteos trace notifications show [--environment <slug>] [--json]
|
|
7998
|
+
siteos trace notifications destinations [--environment <slug>] [--cursor <cursor>] [--json]
|
|
7999
|
+
siteos trace notifications save --input <settings.json> [--environment <slug>] [--json]
|
|
8000
|
+
siteos trace notifications retry --input <retry.json> [--environment <slug>] [--json]
|
|
8001
|
+
siteos trace schema restart --input <baseline.json> [--environment <slug>] [--json]
|
|
7959
8002
|
siteos trace destinations [--environment <slug>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
7960
8003
|
siteos trace events [--environment <slug>] [--provider <provider>] [--event <name>] [--search <text>] [--state <all|new|issues|tracked|ignored>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
7961
8004
|
siteos trace properties [--environment <slug>] [--provider <provider>] [--event <name>] [--property <name>] [--search <text>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
7962
|
-
siteos trace issues [--environment <slug>] [--provider <provider>] [--event <name>] [--state <all|active|snoozed|resolved|new>] [--rule <rule>] [--search <text>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
7963
|
-
siteos trace observations [--environment <slug>] [--provider <provider>] [--event <name>] [--kind <kind>] [--page-view <uuid>] [--search <text>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
8005
|
+
siteos trace issues [--environment <slug>] [--provider <provider>] [--event <name>] [--state <all|active|snoozed|resolved|new>] [--rule <rule>] [--container-id <GTM-ID>] [--tag-id <id>] [--search <text>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
8006
|
+
siteos trace observations [--environment <slug>] [--provider <provider>] [--event <name>] [--kind <kind>] [--page-view <uuid>] [--container-id <GTM-ID>] [--tag-id <id>] [--result <result>] [--search <text>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
7964
8007
|
siteos trace issue show --id <uuid> [--environment <slug>] [--cursor <finding-cursor>] [--json]
|
|
7965
8008
|
siteos trace observation show --batch-id <uuid> --event-id <uuid> [--environment <slug>] [--json]
|
|
7966
8009
|
siteos trace installation <show|ensure|save|publish> [--environment <slug>] [--input <draft.json>] [--json]
|
|
@@ -7974,7 +8017,7 @@ Use --expected-draft-version when publishing a reviewed tracking plan; a conflic
|
|
|
7974
8017
|
Explorer commands require the matching Trace server. They read one page and return nextCursor.
|
|
7975
8018
|
Reuse the same filters with that cursor; omit it to start a fresh time window.
|
|
7976
8019
|
Providers: siteos_analytics, ga4, google_ads, hubspot, meta, custom (data layer source).
|
|
7977
|
-
Kinds: data_layer, fetch, xhr, beacon, resource, consent, heartbeat, runtime_diagnostic.
|
|
8020
|
+
Kinds: data_layer, fetch, xhr, beacon, resource, consent, heartbeat, runtime_diagnostic, tag_execution.
|
|
7978
8021
|
Lists also accept --provider, --event, --property, --page-view, --search, --state, --rule and --kind.
|
|
7979
8022
|
Destinations are observed analytics services; a data layer event alone does not prove delivery.`,
|
|
7980
8023
|
integrations: `Manage shared Organization connections and notification destinations.
|
|
@@ -8016,6 +8059,9 @@ async function runServiceCommand(service, options) {
|
|
|
8016
8059
|
event: { type: "string" },
|
|
8017
8060
|
property: { type: "string" },
|
|
8018
8061
|
"page-view": { type: "string" },
|
|
8062
|
+
"container-id": { type: "string" },
|
|
8063
|
+
"tag-id": { type: "string" },
|
|
8064
|
+
result: { type: "string" },
|
|
8019
8065
|
search: { type: "string" },
|
|
8020
8066
|
state: { type: "string" },
|
|
8021
8067
|
rule: { type: "string" },
|
|
@@ -8050,6 +8096,9 @@ async function runServiceCommand(service, options) {
|
|
|
8050
8096
|
environments: [],
|
|
8051
8097
|
report: ["environment"],
|
|
8052
8098
|
...TRACE_EXPLORER_FLAGS,
|
|
8099
|
+
"notifications save": ["environment", "input"],
|
|
8100
|
+
"notifications retry": ["environment", "input"],
|
|
8101
|
+
"schema restart": ["environment", "input"],
|
|
8053
8102
|
...Object.fromEntries(
|
|
8054
8103
|
["installation", "tracking-plan"].flatMap(
|
|
8055
8104
|
(section) => ["show", "ensure", "save", "publish"].map((operation) => [
|
|
@@ -8246,7 +8295,7 @@ async function runServiceCommand(service, options) {
|
|
|
8246
8295
|
result = await request(site);
|
|
8247
8296
|
else if (action === "environments" && positionals.length === 1)
|
|
8248
8297
|
result = await request(`${site}/environments`);
|
|
8249
|
-
else if (action === "report" || action === "installation" || action === "tracking-plan" || explorerSuffix !== null) {
|
|
8298
|
+
else if (action === "notifications" || action === "schema" || action === "report" || action === "installation" || action === "tracking-plan" || explorerSuffix !== null) {
|
|
8250
8299
|
const response = z13.object({
|
|
8251
8300
|
environments: z13.array(
|
|
8252
8301
|
z13.object({ id: z13.string(), slug: z13.string() })
|
|
@@ -8275,6 +8324,12 @@ async function runServiceCommand(service, options) {
|
|
|
8275
8324
|
const base = `/environments/${encodeURIComponent(matches[0].id)}`;
|
|
8276
8325
|
if (explorerSuffix !== null) {
|
|
8277
8326
|
result = await request(`${base}${explorerSuffix}`);
|
|
8327
|
+
} else if (route === "notifications retry" || route === "schema restart") {
|
|
8328
|
+
result = await request(
|
|
8329
|
+
`${base}/${route === "schema restart" ? "schema-baselines/reset" : "notification-retries"}`,
|
|
8330
|
+
"POST",
|
|
8331
|
+
await inputFile()
|
|
8332
|
+
);
|
|
8278
8333
|
} else if (action === "report" && positionals.length === 1) {
|
|
8279
8334
|
const detail = z13.object({
|
|
8280
8335
|
site: z13.object({
|
|
@@ -8710,16 +8765,8 @@ async function runAnalyticsCommand(options) {
|
|
|
8710
8765
|
}
|
|
8711
8766
|
}
|
|
8712
8767
|
|
|
8713
|
-
// src/services/seo-command.ts
|
|
8714
|
-
import {
|
|
8715
|
-
import path28 from "path";
|
|
8716
|
-
import { parseArgs as parseArgs8 } from "util";
|
|
8717
|
-
import { z as z19 } from "zod";
|
|
8718
|
-
|
|
8719
|
-
// src/services/seo-research-command.ts
|
|
8720
|
-
import { randomUUID as randomUUID6 } from "crypto";
|
|
8721
|
-
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
8722
|
-
import { isDeepStrictEqual, parseArgs as parseArgs5 } from "util";
|
|
8768
|
+
// src/services/seo-repair-command.ts
|
|
8769
|
+
import { parseArgs as parseArgs5 } from "util";
|
|
8723
8770
|
import { z as z16 } from "zod";
|
|
8724
8771
|
|
|
8725
8772
|
// src/services/seo-report-client.ts
|
|
@@ -8823,7 +8870,110 @@ function seoReportFailure(cause, json, idempotencyKey) {
|
|
|
8823
8870
|
};
|
|
8824
8871
|
}
|
|
8825
8872
|
|
|
8873
|
+
// src/services/seo-repair-command.ts
|
|
8874
|
+
async function runSeoRepairCommand(options) {
|
|
8875
|
+
const json = options.args.includes("--json");
|
|
8876
|
+
try {
|
|
8877
|
+
const { positionals, values } = parseArgs5({
|
|
8878
|
+
args: options.args,
|
|
8879
|
+
allowPositionals: true,
|
|
8880
|
+
strict: true,
|
|
8881
|
+
options: {
|
|
8882
|
+
json: { type: "boolean" },
|
|
8883
|
+
environment: { type: "string" },
|
|
8884
|
+
resource: { type: "string" },
|
|
8885
|
+
audit: { type: "string" },
|
|
8886
|
+
url: { type: "string", multiple: true },
|
|
8887
|
+
rule: { type: "string" }
|
|
8888
|
+
}
|
|
8889
|
+
});
|
|
8890
|
+
const recheck = positionals[0] === "recheck";
|
|
8891
|
+
if (positionals.length !== 1 || !recheck && positionals[0] !== "repair" || recheck && values.rule)
|
|
8892
|
+
throw new Error(
|
|
8893
|
+
"Use siteos seo repair or siteos seo recheck with documented flags."
|
|
8894
|
+
);
|
|
8895
|
+
if (!values.audit || values.audit.length > 160 || !values.url?.length || values.url.length > 20)
|
|
8896
|
+
throw new Error(
|
|
8897
|
+
"Choose a source --audit and between 1 and 20 --url values."
|
|
8898
|
+
);
|
|
8899
|
+
if (values.rule && values.rule.length > 120)
|
|
8900
|
+
throw new Error("Use a documented rule ID.");
|
|
8901
|
+
for (const value of values.url) {
|
|
8902
|
+
const url = new URL(value);
|
|
8903
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.port || value.length > 2048)
|
|
8904
|
+
throw new Error("Use eligible public HTTP(S) URLs.");
|
|
8905
|
+
}
|
|
8906
|
+
const client = await seoReportClient(options, values.environment);
|
|
8907
|
+
if (values.resource && client.resourceId !== values.resource)
|
|
8908
|
+
throw new Error(
|
|
8909
|
+
"The selected Project environment does not match --resource. Select the environment from the repair brief first."
|
|
8910
|
+
);
|
|
8911
|
+
const urls = [...new Set(values.url)];
|
|
8912
|
+
const response = recheck ? await client.request("/rechecks", "seo:audits:write", {
|
|
8913
|
+
auditId: values.audit,
|
|
8914
|
+
urls
|
|
8915
|
+
}) : await client.request("/repair-brief", "seo:workspace:read", {
|
|
8916
|
+
audit: values.audit,
|
|
8917
|
+
urls,
|
|
8918
|
+
...values.rule ? { rule: values.rule } : {}
|
|
8919
|
+
});
|
|
8920
|
+
const record = versionedReport.parse(await response.json());
|
|
8921
|
+
if (recheck) {
|
|
8922
|
+
z16.object({
|
|
8923
|
+
id: z16.string(),
|
|
8924
|
+
resourceId: z16.literal(client.resourceId),
|
|
8925
|
+
organizationId: z16.literal(client.organizationId),
|
|
8926
|
+
state: z16.literal("queued")
|
|
8927
|
+
}).parse(record.audit);
|
|
8928
|
+
return { exitCode: 0, stdout: JSON.stringify(record, null, 2) };
|
|
8929
|
+
}
|
|
8930
|
+
const brief = z16.object({
|
|
8931
|
+
schemaVersion: z16.literal(1),
|
|
8932
|
+
context: z16.object({
|
|
8933
|
+
auditId: z16.literal(values.audit),
|
|
8934
|
+
resourceId: z16.literal(client.resourceId),
|
|
8935
|
+
organizationId: z16.literal(client.organizationId),
|
|
8936
|
+
selectedUrls: z16.array(z16.string()).min(1).max(20),
|
|
8937
|
+
ruleId: z16.literal(values.rule ?? null)
|
|
8938
|
+
}),
|
|
8939
|
+
evidence: z16.array(
|
|
8940
|
+
z16.object({
|
|
8941
|
+
url: z16.string(),
|
|
8942
|
+
findings: z16.array(z16.unknown()).max(12)
|
|
8943
|
+
})
|
|
8944
|
+
).min(1).max(20),
|
|
8945
|
+
suggestedGroups: z16.array(z16.unknown()),
|
|
8946
|
+
verificationCommand: z16.string().min(1),
|
|
8947
|
+
text: z16.string().min(1)
|
|
8948
|
+
}).parse(record);
|
|
8949
|
+
const canonical = (value) => {
|
|
8950
|
+
const url = new URL(value);
|
|
8951
|
+
url.hash = "";
|
|
8952
|
+
return url.href;
|
|
8953
|
+
};
|
|
8954
|
+
const expected = new Set(urls.map(canonical));
|
|
8955
|
+
if (brief.context.selectedUrls.length !== expected.size || new Set(brief.context.selectedUrls).size !== expected.size || brief.context.selectedUrls.some((url) => !expected.has(url)) || brief.evidence.length !== expected.size || new Set(brief.evidence.map((page) => page.url)).size !== expected.size || brief.evidence.some((page) => !expected.has(page.url)))
|
|
8956
|
+
throw new Error("The repair brief does not match the selected URLs.");
|
|
8957
|
+
return {
|
|
8958
|
+
exitCode: 0,
|
|
8959
|
+
stdout: json ? JSON.stringify(record, null, 2) : brief.text
|
|
8960
|
+
};
|
|
8961
|
+
} catch (cause) {
|
|
8962
|
+
return seoReportFailure(cause, json);
|
|
8963
|
+
}
|
|
8964
|
+
}
|
|
8965
|
+
|
|
8966
|
+
// src/services/seo-command.ts
|
|
8967
|
+
import { writeFile as writeFile10 } from "fs/promises";
|
|
8968
|
+
import path28 from "path";
|
|
8969
|
+
import { parseArgs as parseArgs9 } from "util";
|
|
8970
|
+
import { z as z20 } from "zod";
|
|
8971
|
+
|
|
8826
8972
|
// src/services/seo-research-command.ts
|
|
8973
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
8974
|
+
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
8975
|
+
import { isDeepStrictEqual, parseArgs as parseArgs6 } from "util";
|
|
8976
|
+
import { z as z17 } from "zod";
|
|
8827
8977
|
var RESEARCH_HELP = `
|
|
8828
8978
|
siteos seo research summary [--environment <slug>] [--json]
|
|
8829
8979
|
siteos seo research status --kind <kind> [--environment <slug>] [--json]
|
|
@@ -8864,11 +9014,11 @@ var kinds = [
|
|
|
8864
9014
|
"brand",
|
|
8865
9015
|
"ai-visibility"
|
|
8866
9016
|
];
|
|
8867
|
-
var requestSchema =
|
|
8868
|
-
kind:
|
|
8869
|
-
target:
|
|
9017
|
+
var requestSchema = z17.object({
|
|
9018
|
+
kind: z17.enum(["domain", ...kinds]).transform((kind) => kind === "domain" ? "competitors" : kind),
|
|
9019
|
+
target: z17.string().min(1).max(253)
|
|
8870
9020
|
}).passthrough();
|
|
8871
|
-
var runStates =
|
|
9021
|
+
var runStates = z17.enum([
|
|
8872
9022
|
"queued",
|
|
8873
9023
|
"running",
|
|
8874
9024
|
"completed",
|
|
@@ -8884,7 +9034,7 @@ var csvCell = (value) => {
|
|
|
8884
9034
|
async function runSeoResearchCommand(options) {
|
|
8885
9035
|
let idempotencyKey;
|
|
8886
9036
|
try {
|
|
8887
|
-
const { values, positionals } =
|
|
9037
|
+
const { values, positionals } = parseArgs6({
|
|
8888
9038
|
args: options.args.slice(1),
|
|
8889
9039
|
strict: true,
|
|
8890
9040
|
allowPositionals: true,
|
|
@@ -8965,26 +9115,26 @@ async function runSeoResearchCommand(options) {
|
|
|
8965
9115
|
);
|
|
8966
9116
|
}
|
|
8967
9117
|
const client = await seoReportClient(options, values.environment);
|
|
8968
|
-
const resourceSchema =
|
|
8969
|
-
id:
|
|
8970
|
-
organizationId:
|
|
9118
|
+
const resourceSchema = z17.object({
|
|
9119
|
+
id: z17.literal(client.resourceId),
|
|
9120
|
+
organizationId: z17.literal(client.organizationId)
|
|
8971
9121
|
}).passthrough();
|
|
8972
|
-
const runSchema =
|
|
8973
|
-
id:
|
|
8974
|
-
resourceId:
|
|
8975
|
-
organizationId:
|
|
8976
|
-
websiteUrl:
|
|
9122
|
+
const runSchema = z17.object({
|
|
9123
|
+
id: z17.string(),
|
|
9124
|
+
resourceId: z17.literal(client.resourceId),
|
|
9125
|
+
organizationId: z17.literal(client.organizationId),
|
|
9126
|
+
websiteUrl: z17.string(),
|
|
8977
9127
|
request: requestSchema,
|
|
8978
9128
|
state: runStates,
|
|
8979
|
-
createdAt:
|
|
8980
|
-
finishedAt:
|
|
8981
|
-
parts:
|
|
8982
|
-
|
|
8983
|
-
key:
|
|
8984
|
-
state:
|
|
8985
|
-
error:
|
|
8986
|
-
dataset:
|
|
8987
|
-
observedAt:
|
|
9129
|
+
createdAt: z17.string(),
|
|
9130
|
+
finishedAt: z17.string().nullable(),
|
|
9131
|
+
parts: z17.array(
|
|
9132
|
+
z17.object({
|
|
9133
|
+
key: z17.string(),
|
|
9134
|
+
state: z17.enum(["completed", "failed"]),
|
|
9135
|
+
error: z17.string().nullable(),
|
|
9136
|
+
dataset: z17.record(z17.unknown()).nullable(),
|
|
9137
|
+
observedAt: z17.string()
|
|
8988
9138
|
}).passthrough()
|
|
8989
9139
|
)
|
|
8990
9140
|
}).passthrough();
|
|
@@ -8998,36 +9148,36 @@ async function runSeoResearchCommand(options) {
|
|
|
8998
9148
|
const query = `?kind=${encodeURIComponent(values.kind ?? "rankings")}`;
|
|
8999
9149
|
let record;
|
|
9000
9150
|
if (action.startsWith("serp ")) {
|
|
9001
|
-
const snapshotSchema =
|
|
9002
|
-
id:
|
|
9003
|
-
organizationId:
|
|
9004
|
-
resourceId:
|
|
9005
|
-
sourceRunId:
|
|
9151
|
+
const snapshotSchema = z17.object({
|
|
9152
|
+
id: z17.string(),
|
|
9153
|
+
organizationId: z17.literal(client.organizationId),
|
|
9154
|
+
resourceId: z17.literal(client.resourceId),
|
|
9155
|
+
sourceRunId: z17.literal(id),
|
|
9006
9156
|
request: requestSchema,
|
|
9007
|
-
keywordKey:
|
|
9157
|
+
keywordKey: z17.literal(
|
|
9008
9158
|
values.keyword.normalize("NFKC").trim().toLowerCase().replace(/\s+/gu, " ")
|
|
9009
9159
|
),
|
|
9010
|
-
state:
|
|
9160
|
+
state: z17.enum([
|
|
9011
9161
|
"queued",
|
|
9012
9162
|
"running",
|
|
9013
9163
|
"completed",
|
|
9014
9164
|
"failed",
|
|
9015
9165
|
"cancelled"
|
|
9016
9166
|
]),
|
|
9017
|
-
dataset:
|
|
9018
|
-
type:
|
|
9019
|
-
keyword:
|
|
9020
|
-
country:
|
|
9021
|
-
language:
|
|
9022
|
-
device:
|
|
9023
|
-
observedAt:
|
|
9024
|
-
rows:
|
|
9025
|
-
|
|
9026
|
-
position:
|
|
9027
|
-
title:
|
|
9028
|
-
url:
|
|
9029
|
-
domain:
|
|
9030
|
-
description:
|
|
9167
|
+
dataset: z17.object({
|
|
9168
|
+
type: z17.literal("serp"),
|
|
9169
|
+
keyword: z17.string(),
|
|
9170
|
+
country: z17.string(),
|
|
9171
|
+
language: z17.string(),
|
|
9172
|
+
device: z17.enum(["desktop", "mobile"]),
|
|
9173
|
+
observedAt: z17.string(),
|
|
9174
|
+
rows: z17.array(
|
|
9175
|
+
z17.object({
|
|
9176
|
+
position: z17.number(),
|
|
9177
|
+
title: z17.string(),
|
|
9178
|
+
url: z17.string(),
|
|
9179
|
+
domain: z17.string(),
|
|
9180
|
+
description: z17.string()
|
|
9031
9181
|
})
|
|
9032
9182
|
)
|
|
9033
9183
|
}).nullable()
|
|
@@ -9120,9 +9270,9 @@ async function runSeoResearchCommand(options) {
|
|
|
9120
9270
|
name: values.name.trim(),
|
|
9121
9271
|
...values.id ? { id: values.id } : {}
|
|
9122
9272
|
});
|
|
9123
|
-
const saved =
|
|
9124
|
-
id:
|
|
9125
|
-
name:
|
|
9273
|
+
const saved = z17.object({
|
|
9274
|
+
id: z17.string(),
|
|
9275
|
+
name: z17.literal(values.name.trim()),
|
|
9126
9276
|
request: requestSchema
|
|
9127
9277
|
}).parse(record.saved);
|
|
9128
9278
|
if (values.id && saved.id !== values.id || !isDeepStrictEqual(saved.request, plan.request))
|
|
@@ -9136,23 +9286,23 @@ async function runSeoResearchCommand(options) {
|
|
|
9136
9286
|
action === "cancel" ? "run" : "write",
|
|
9137
9287
|
{}
|
|
9138
9288
|
);
|
|
9139
|
-
|
|
9289
|
+
z17.literal(true).parse(
|
|
9140
9290
|
record[action === "cancel" ? "cancelled" : "removed"]
|
|
9141
9291
|
);
|
|
9142
9292
|
} else if (action === "summary") {
|
|
9143
9293
|
record = await get("/summary");
|
|
9144
9294
|
resourceSchema.parse(record.resource);
|
|
9145
|
-
|
|
9295
|
+
z17.array(z17.object({ kind: z17.enum(kinds), summary: z17.unknown() })).parse(
|
|
9146
9296
|
record.checks
|
|
9147
9297
|
);
|
|
9148
9298
|
} else if (["status", "history", "saved list"].includes(action)) {
|
|
9149
9299
|
const view = await get(query);
|
|
9150
9300
|
resourceSchema.parse(view.resource);
|
|
9151
|
-
const runs =
|
|
9152
|
-
const saved =
|
|
9153
|
-
|
|
9154
|
-
id:
|
|
9155
|
-
name:
|
|
9301
|
+
const runs = z17.array(runSchema).parse(view.runs);
|
|
9302
|
+
const saved = z17.array(
|
|
9303
|
+
z17.object({
|
|
9304
|
+
id: z17.string(),
|
|
9305
|
+
name: z17.string(),
|
|
9156
9306
|
request: requestSchema
|
|
9157
9307
|
}).passthrough()
|
|
9158
9308
|
).parse(view.saved);
|
|
@@ -9268,8 +9418,8 @@ async function runSeoResearchCommand(options) {
|
|
|
9268
9418
|
}
|
|
9269
9419
|
|
|
9270
9420
|
// src/services/seo-gsc-command.ts
|
|
9271
|
-
import { parseArgs as
|
|
9272
|
-
import { z as
|
|
9421
|
+
import { parseArgs as parseArgs7 } from "util";
|
|
9422
|
+
import { z as z18 } from "zod";
|
|
9273
9423
|
var GSC_HELP = `
|
|
9274
9424
|
siteos seo gsc status [--environment <slug>] [--json]
|
|
9275
9425
|
siteos seo gsc report [--dataset <pages|queries>] [--query <text>] [--filter <all|issues|declining>] [--sort <clicks|change|impressions>] [--page <number>] [--url <page-url>] [--environment <slug>] [--json]
|
|
@@ -9287,7 +9437,7 @@ Bind/disconnect require a current revision and separate settings authority. Disc
|
|
|
9287
9437
|
`;
|
|
9288
9438
|
async function runSeoGscCommand(options) {
|
|
9289
9439
|
try {
|
|
9290
|
-
const { values, positionals } =
|
|
9440
|
+
const { values, positionals } = parseArgs7({
|
|
9291
9441
|
args: options.args.slice(1),
|
|
9292
9442
|
strict: true,
|
|
9293
9443
|
allowPositionals: true,
|
|
@@ -9369,13 +9519,13 @@ async function runSeoGscCommand(options) {
|
|
|
9369
9519
|
`seo:search:${action === "sync" ? "sync" : writing ? "write" : "read"}`,
|
|
9370
9520
|
body
|
|
9371
9521
|
);
|
|
9372
|
-
const runSchema =
|
|
9373
|
-
id:
|
|
9374
|
-
resourceId:
|
|
9375
|
-
organizationId:
|
|
9376
|
-
websiteUrl:
|
|
9377
|
-
siteUrl:
|
|
9378
|
-
state:
|
|
9522
|
+
const runSchema = z18.object({
|
|
9523
|
+
id: z18.string(),
|
|
9524
|
+
resourceId: z18.literal(client.resourceId),
|
|
9525
|
+
organizationId: z18.literal(client.organizationId),
|
|
9526
|
+
websiteUrl: z18.string(),
|
|
9527
|
+
siteUrl: z18.string(),
|
|
9528
|
+
state: z18.enum([
|
|
9379
9529
|
"queued",
|
|
9380
9530
|
"running",
|
|
9381
9531
|
"completed",
|
|
@@ -9383,32 +9533,32 @@ async function runSeoGscCommand(options) {
|
|
|
9383
9533
|
"failed",
|
|
9384
9534
|
"cancelled"
|
|
9385
9535
|
]),
|
|
9386
|
-
dates:
|
|
9536
|
+
dates: z18.unknown()
|
|
9387
9537
|
}).passthrough();
|
|
9388
|
-
const bindingSchema =
|
|
9389
|
-
resourceId:
|
|
9390
|
-
organizationId:
|
|
9391
|
-
websiteUrl:
|
|
9392
|
-
siteUrl:
|
|
9393
|
-
revision:
|
|
9538
|
+
const bindingSchema = z18.object({
|
|
9539
|
+
resourceId: z18.literal(client.resourceId),
|
|
9540
|
+
organizationId: z18.literal(client.organizationId),
|
|
9541
|
+
websiteUrl: z18.string(),
|
|
9542
|
+
siteUrl: z18.string(),
|
|
9543
|
+
revision: z18.number().int().positive()
|
|
9394
9544
|
}).passthrough();
|
|
9395
|
-
const metrics =
|
|
9396
|
-
clicks:
|
|
9397
|
-
impressions:
|
|
9398
|
-
ctr:
|
|
9399
|
-
position:
|
|
9545
|
+
const metrics = z18.object({
|
|
9546
|
+
clicks: z18.number(),
|
|
9547
|
+
impressions: z18.number(),
|
|
9548
|
+
ctr: z18.number(),
|
|
9549
|
+
position: z18.number()
|
|
9400
9550
|
}).passthrough().nullable();
|
|
9401
9551
|
const validateView = (data) => {
|
|
9402
9552
|
const record2 = versionedReport.parse(data);
|
|
9403
|
-
|
|
9553
|
+
z18.literal(client.resourceId).parse(record2.resourceId);
|
|
9404
9554
|
bindingSchema.nullable().parse(record2.binding);
|
|
9405
9555
|
runSchema.nullable().parse(record2.latest);
|
|
9406
9556
|
runSchema.nullable().parse(record2.report);
|
|
9407
|
-
|
|
9408
|
-
|
|
9557
|
+
z18.array(
|
|
9558
|
+
z18.object({ key: z18.string(), current: metrics, previous: metrics }).passthrough()
|
|
9409
9559
|
).parse(record2.rows);
|
|
9410
|
-
|
|
9411
|
-
|
|
9560
|
+
z18.number().int().nonnegative().parse(record2.total);
|
|
9561
|
+
z18.literal(values.dataset ?? "pages").parse(record2.dataset);
|
|
9412
9562
|
return record2;
|
|
9413
9563
|
};
|
|
9414
9564
|
if (action === "export") {
|
|
@@ -9424,9 +9574,9 @@ async function runSeoGscCommand(options) {
|
|
|
9424
9574
|
const text = await response.text();
|
|
9425
9575
|
if (values.format === "json") {
|
|
9426
9576
|
const report = validateView(JSON.parse(text));
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9577
|
+
z18.literal(reportId).parse(runSchema.parse(report.report).id);
|
|
9578
|
+
z18.array(z18.unknown()).length(rows).parse(report.rows);
|
|
9579
|
+
z18.literal(truncated === "true").parse(report.truncated);
|
|
9430
9580
|
}
|
|
9431
9581
|
const output = await writeSeoReport(options, values.output, text);
|
|
9432
9582
|
return {
|
|
@@ -9447,7 +9597,7 @@ async function runSeoGscCommand(options) {
|
|
|
9447
9597
|
};
|
|
9448
9598
|
}
|
|
9449
9599
|
const record = versionedReport.parse(await response.json());
|
|
9450
|
-
if (action === "disconnect")
|
|
9600
|
+
if (action === "disconnect") z18.literal(true).parse(record.unbound);
|
|
9451
9601
|
else if (writing) {
|
|
9452
9602
|
runSchema.parse(record.run);
|
|
9453
9603
|
if (action === "bind") {
|
|
@@ -9469,8 +9619,8 @@ import { randomUUID as randomUUID7 } from "crypto";
|
|
|
9469
9619
|
import { writeFile as writeFile9 } from "fs/promises";
|
|
9470
9620
|
import path27 from "path";
|
|
9471
9621
|
import { setTimeout as setTimeout3 } from "timers/promises";
|
|
9472
|
-
import { parseArgs as
|
|
9473
|
-
import { z as
|
|
9622
|
+
import { parseArgs as parseArgs8 } from "util";
|
|
9623
|
+
import { z as z19 } from "zod";
|
|
9474
9624
|
var PERFORMANCE_HELP = `
|
|
9475
9625
|
siteos seo performance run --audit <id> --url <url> [--url <url>...] [--device <mobile|desktop>] [--idempotency-key <key>] [--environment <slug>] [--json]
|
|
9476
9626
|
siteos seo performance list [--device <mobile|desktop>] [--environment <slug>] [--json]
|
|
@@ -9487,7 +9637,7 @@ Reuse the returned idempotency key after an uncertain run response. Wait default
|
|
|
9487
9637
|
async function runSeoPerformanceCommand(options) {
|
|
9488
9638
|
let idempotencyKey;
|
|
9489
9639
|
try {
|
|
9490
|
-
const { values, positionals } =
|
|
9640
|
+
const { values, positionals } = parseArgs8({
|
|
9491
9641
|
args: options.args.slice(1),
|
|
9492
9642
|
strict: true,
|
|
9493
9643
|
allowPositionals: true,
|
|
@@ -9558,12 +9708,12 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9558
9708
|
const runtime = commonProjectRuntime(options);
|
|
9559
9709
|
const writing = ["run", "cancel"].includes(action);
|
|
9560
9710
|
const scope = writing ? "seo:audits:write" : "seo:workspace:read";
|
|
9561
|
-
const batchSchema =
|
|
9562
|
-
id:
|
|
9563
|
-
resourceId:
|
|
9564
|
-
organizationId:
|
|
9565
|
-
sourceAuditId:
|
|
9566
|
-
state:
|
|
9711
|
+
const batchSchema = z19.object({
|
|
9712
|
+
id: z19.string(),
|
|
9713
|
+
resourceId: z19.literal(context.resourceId),
|
|
9714
|
+
organizationId: z19.literal(context.overview.project.organizationId),
|
|
9715
|
+
sourceAuditId: z19.string(),
|
|
9716
|
+
state: z19.enum([
|
|
9567
9717
|
"queued",
|
|
9568
9718
|
"running",
|
|
9569
9719
|
"completed",
|
|
@@ -9571,8 +9721,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9571
9721
|
"failed",
|
|
9572
9722
|
"cancelled"
|
|
9573
9723
|
]),
|
|
9574
|
-
device:
|
|
9575
|
-
urls:
|
|
9724
|
+
device: z19.enum(["mobile", "desktop"]),
|
|
9725
|
+
urls: z19.array(z19.string()).min(1).max(10)
|
|
9576
9726
|
}).passthrough();
|
|
9577
9727
|
const query = new URLSearchParams();
|
|
9578
9728
|
if (values.device) query.set("device", values.device);
|
|
@@ -9620,10 +9770,10 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9620
9770
|
);
|
|
9621
9771
|
const text = await response.text();
|
|
9622
9772
|
if (values.format === "json") {
|
|
9623
|
-
const parsed =
|
|
9624
|
-
contractVersion:
|
|
9773
|
+
const parsed = z19.object({
|
|
9774
|
+
contractVersion: z19.literal(1),
|
|
9625
9775
|
batch: batchSchema,
|
|
9626
|
-
pages:
|
|
9776
|
+
pages: z19.array(z19.unknown())
|
|
9627
9777
|
}).parse(JSON.parse(text));
|
|
9628
9778
|
if (parsed.batch.id !== id)
|
|
9629
9779
|
throw new Error(
|
|
@@ -9646,8 +9796,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9646
9796
|
}
|
|
9647
9797
|
const data = await response.json();
|
|
9648
9798
|
if (!response.ok) {
|
|
9649
|
-
const error =
|
|
9650
|
-
error:
|
|
9799
|
+
const error = z19.object({
|
|
9800
|
+
error: z19.object({ code: z19.string(), message: z19.string().max(500) })
|
|
9651
9801
|
}).safeParse(data);
|
|
9652
9802
|
throw new SiteOSAuthApiError({
|
|
9653
9803
|
code: error.success ? error.data.error.code : "SEO_REQUEST_FAILED",
|
|
@@ -9655,8 +9805,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9655
9805
|
status: response.status
|
|
9656
9806
|
});
|
|
9657
9807
|
}
|
|
9658
|
-
const record =
|
|
9659
|
-
if (action === "cancel")
|
|
9808
|
+
const record = z19.object({ contractVersion: z19.literal(1) }).passthrough().parse(data);
|
|
9809
|
+
if (action === "cancel") z19.literal(true).parse(record.cancelled);
|
|
9660
9810
|
else if (action === "run") {
|
|
9661
9811
|
const accepted = batchSchema.parse(record.batch);
|
|
9662
9812
|
const normalize = (url) => {
|
|
@@ -9669,8 +9819,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9669
9819
|
"The queued check does not match the requested source, device and URLs."
|
|
9670
9820
|
);
|
|
9671
9821
|
} else {
|
|
9672
|
-
|
|
9673
|
-
|
|
9822
|
+
z19.literal(context.resourceId).parse(record.resourceId);
|
|
9823
|
+
z19.array(batchSchema).parse(record.batches);
|
|
9674
9824
|
const selected = batchSchema.nullable().parse(record.batch);
|
|
9675
9825
|
if (id && selected?.id !== id)
|
|
9676
9826
|
throw new Error(
|
|
@@ -9697,7 +9847,7 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9697
9847
|
} catch (cause) {
|
|
9698
9848
|
const error = {
|
|
9699
9849
|
code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
|
|
9700
|
-
message: cause instanceof
|
|
9850
|
+
message: cause instanceof z19.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The performance command failed."
|
|
9701
9851
|
};
|
|
9702
9852
|
return {
|
|
9703
9853
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
@@ -9733,7 +9883,8 @@ Usage:
|
|
|
9733
9883
|
siteos seo pages [--audit <id>] [--query <text>] [--url <url>] [--page <number>] [--environment <slug>] [--json]
|
|
9734
9884
|
siteos seo issues [--audit <id>] [--rule <id>] [--page <number>] [--environment <slug>] [--json]
|
|
9735
9885
|
siteos seo changes [--audit <id>] [--state <new|reopened|still_present|resolved|not_rechecked>] [--page <number>] [--environment <slug>] [--json]
|
|
9736
|
-
siteos seo
|
|
9886
|
+
siteos seo repair --audit <id> --url <url> [--url <url>...] [--rule <id>] [--resource <expected-id>] [--environment <slug>] [--json]
|
|
9887
|
+
siteos seo recheck --audit <id> --url <url> [--url <url>...] [--resource <expected-id>] [--environment <slug>] [--json]
|
|
9737
9888
|
siteos seo issue <ignore|restore> --audit <id> --url <url> --rule <id> --reason <text> --revision <number> [--environment <slug>] [--json]
|
|
9738
9889
|
siteos seo schedule show [--environment <slug>] [--json]
|
|
9739
9890
|
siteos seo schedule set --enabled <true|false> --weekday <1-7> --time <HH:mm> --timezone <IANA> --revision <number> [--environment <slug>] [--json]
|
|
@@ -9749,7 +9900,9 @@ ${GSC_HELP.trim().split("\n\n")[0]}
|
|
|
9749
9900
|
Schedule and notification writes require an owner/admin and the saved revision (initially 0).
|
|
9750
9901
|
Export writes all matching rows to a new file; existing files are never overwritten.
|
|
9751
9902
|
Runs are queued. Read audit show until terminal; an accepted run is not a completed check.
|
|
9752
|
-
|
|
9903
|
+
Repair reads a bounded brief for selected saved evidence; it does not start work.
|
|
9904
|
+
Recheck accepts 1\u201320 URLs observed in the source audit. Cross-page rules require a full audit.
|
|
9905
|
+
--resource verifies the selected environment binding before requesting a brief or recheck.
|
|
9753
9906
|
Read the current disposition revision before ignore/restore; use 0 if no decision exists.
|
|
9754
9907
|
Setup: siteos project connect seo. No crawl runs during setup.
|
|
9755
9908
|
${PERFORMANCE_HELP.trim().split("\n\n").slice(1).join("\n\n")}
|
|
@@ -9762,9 +9915,11 @@ async function runSeoCommand(options) {
|
|
|
9762
9915
|
return runSeoPerformanceCommand(options);
|
|
9763
9916
|
if (options.args[0] === "research") return runSeoResearchCommand(options);
|
|
9764
9917
|
if (options.args[0] === "gsc") return runSeoGscCommand(options);
|
|
9918
|
+
if (["repair", "recheck"].includes(options.args[0] ?? ""))
|
|
9919
|
+
return runSeoRepairCommand(options);
|
|
9765
9920
|
const json = options.args.includes("--json");
|
|
9766
9921
|
try {
|
|
9767
|
-
const { positionals, values } =
|
|
9922
|
+
const { positionals, values } = parseArgs9({
|
|
9768
9923
|
args: options.args,
|
|
9769
9924
|
strict: true,
|
|
9770
9925
|
allowPositionals: true,
|
|
@@ -9827,7 +9982,6 @@ async function runSeoCommand(options) {
|
|
|
9827
9982
|
pages: { flags: ["audit", "url", "query", "page"], args: 1 },
|
|
9828
9983
|
issues: { flags: ["audit", "rule", "page"], args: 1 },
|
|
9829
9984
|
changes: { flags: ["audit", "state", "page"], args: 1 },
|
|
9830
|
-
recheck: { flags: ["audit", "url"], args: 1 },
|
|
9831
9985
|
"issue ignore": {
|
|
9832
9986
|
flags: ["audit", "url", "rule", "reason", "revision"],
|
|
9833
9987
|
args: 2
|
|
@@ -9844,8 +9998,6 @@ async function runSeoCommand(options) {
|
|
|
9844
9998
|
throw new Error(
|
|
9845
9999
|
"Invalid SEO operation or flags. Run `siteos seo --help`."
|
|
9846
10000
|
);
|
|
9847
|
-
if (action === "recheck" && (!values.audit || !values.url))
|
|
9848
|
-
throw new Error("Recheck requires --audit and --url.");
|
|
9849
10001
|
if (action === "issue" && ["audit", "url", "rule", "reason", "revision"].some(
|
|
9850
10002
|
(key) => !values[key]
|
|
9851
10003
|
))
|
|
@@ -9895,13 +10047,9 @@ async function runSeoCommand(options) {
|
|
|
9895
10047
|
);
|
|
9896
10048
|
const runtime = commonProjectRuntime(options);
|
|
9897
10049
|
const retryNotification = route === "notifications retry";
|
|
9898
|
-
const writing = retryNotification || setting || [
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
"recheck",
|
|
9902
|
-
"issue ignore",
|
|
9903
|
-
"issue restore"
|
|
9904
|
-
].includes(route);
|
|
10050
|
+
const writing = retryNotification || setting || ["audit run", "audit cancel", "issue ignore", "issue restore"].includes(
|
|
10051
|
+
route
|
|
10052
|
+
);
|
|
9905
10053
|
const scope = retryNotification ? "seo:notifications:write" : setting ? action === "schedule" ? "seo:schedule:write" : "seo:notifications:write" : !writing ? "seo:workspace:read" : action === "issue" ? "seo:issues:write" : "seo:audits:write";
|
|
9906
10054
|
const grant = await runtime.grants.acquire({
|
|
9907
10055
|
audience: "siteos-seo",
|
|
@@ -9930,7 +10078,7 @@ async function runSeoCommand(options) {
|
|
|
9930
10078
|
query.set("state", values.state);
|
|
9931
10079
|
}
|
|
9932
10080
|
if (route === "audit show") query.set("audit", positionals[2]);
|
|
9933
|
-
const suffix = retryNotification ? "/notification-retries" : automation ? setting ? `/${action}` : route === "notifications destinations" ? "/destinations" : "/automation" : action === "export" ? `/export?${query}` : route === "audit run" ? "/audits" : route === "audit cancel" ? `/audits/${encodeURIComponent(positionals[2])}/cancel` : action === "
|
|
10081
|
+
const suffix = retryNotification ? "/notification-retries" : automation ? setting ? `/${action}` : route === "notifications destinations" ? "/destinations" : "/automation" : action === "export" ? `/export?${query}` : route === "audit run" ? "/audits" : route === "audit cancel" ? `/audits/${encodeURIComponent(positionals[2])}/cancel` : action === "issue" ? "/dispositions" : `?${query}`;
|
|
9934
10082
|
const body = retryNotification ? { notificationId: positionals[2] } : route === "schedule set" ? {
|
|
9935
10083
|
enabled: values.enabled === "true",
|
|
9936
10084
|
weekday: Number(values.weekday),
|
|
@@ -9943,7 +10091,7 @@ async function runSeoCommand(options) {
|
|
|
9943
10091
|
minimumSeverity: values.severity,
|
|
9944
10092
|
includeFailures: values.failures === "true",
|
|
9945
10093
|
expectedRevision: Number(values.revision)
|
|
9946
|
-
} : action === "
|
|
10094
|
+
} : action === "issue" ? {
|
|
9947
10095
|
auditId: values.audit,
|
|
9948
10096
|
url: values.url,
|
|
9949
10097
|
ruleId: values.rule,
|
|
@@ -9977,15 +10125,15 @@ async function runSeoCommand(options) {
|
|
|
9977
10125
|
);
|
|
9978
10126
|
const text = await response.text();
|
|
9979
10127
|
if (values.format === "json")
|
|
9980
|
-
|
|
9981
|
-
contractVersion:
|
|
9982
|
-
audit:
|
|
9983
|
-
id:
|
|
9984
|
-
resourceId:
|
|
10128
|
+
z20.object({
|
|
10129
|
+
contractVersion: z20.literal(1),
|
|
10130
|
+
audit: z20.object({
|
|
10131
|
+
id: z20.literal(values.audit),
|
|
10132
|
+
resourceId: z20.literal(context.resourceId)
|
|
9985
10133
|
}),
|
|
9986
|
-
kind:
|
|
9987
|
-
totalRows:
|
|
9988
|
-
rows:
|
|
10134
|
+
kind: z20.literal(values.kind),
|
|
10135
|
+
totalRows: z20.literal(rows),
|
|
10136
|
+
rows: z20.array(z20.unknown()).length(rows)
|
|
9989
10137
|
}).parse(JSON.parse(text));
|
|
9990
10138
|
const output = path28.resolve(options.cwd ?? process.cwd(), values.output);
|
|
9991
10139
|
await writeFile10(output, text, { flag: "wx", mode: 384 });
|
|
@@ -10006,8 +10154,8 @@ async function runSeoCommand(options) {
|
|
|
10006
10154
|
}
|
|
10007
10155
|
const data = await response.json();
|
|
10008
10156
|
if (!response.ok) {
|
|
10009
|
-
const result =
|
|
10010
|
-
error:
|
|
10157
|
+
const result = z20.object({
|
|
10158
|
+
error: z20.object({ code: z20.string(), message: z20.string().max(500) })
|
|
10011
10159
|
}).safeParse(data);
|
|
10012
10160
|
throw new SiteOSAuthApiError({
|
|
10013
10161
|
code: result.success ? result.data.error.code : "SEO_REQUEST_FAILED",
|
|
@@ -10015,34 +10163,34 @@ async function runSeoCommand(options) {
|
|
|
10015
10163
|
status: response.status
|
|
10016
10164
|
});
|
|
10017
10165
|
}
|
|
10018
|
-
const record =
|
|
10166
|
+
const record = z20.object({ contractVersion: z20.literal(1) }).passthrough().parse(data);
|
|
10019
10167
|
if (automation) {
|
|
10020
|
-
|
|
10021
|
-
const schedule =
|
|
10022
|
-
enabled:
|
|
10023
|
-
weekday:
|
|
10024
|
-
time:
|
|
10025
|
-
timeZone:
|
|
10026
|
-
revision:
|
|
10027
|
-
nextRunAt:
|
|
10168
|
+
z20.literal(context.resourceId).parse(record.resourceId);
|
|
10169
|
+
const schedule = z20.object({
|
|
10170
|
+
enabled: z20.boolean(),
|
|
10171
|
+
weekday: z20.number().int().min(1).max(7),
|
|
10172
|
+
time: z20.string(),
|
|
10173
|
+
timeZone: z20.string(),
|
|
10174
|
+
revision: z20.number().int().min(0),
|
|
10175
|
+
nextRunAt: z20.string().nullable()
|
|
10028
10176
|
});
|
|
10029
|
-
const notificationRoute =
|
|
10030
|
-
enabled:
|
|
10031
|
-
minimumSeverity:
|
|
10032
|
-
includeFailures:
|
|
10033
|
-
revision:
|
|
10034
|
-
destinationId:
|
|
10177
|
+
const notificationRoute = z20.object({
|
|
10178
|
+
enabled: z20.boolean(),
|
|
10179
|
+
minimumSeverity: z20.enum(["error", "warning"]),
|
|
10180
|
+
includeFailures: z20.boolean(),
|
|
10181
|
+
revision: z20.number().int().min(0),
|
|
10182
|
+
destinationId: z20.string().nullable()
|
|
10035
10183
|
});
|
|
10036
10184
|
if (retryNotification) {
|
|
10037
|
-
|
|
10038
|
-
|
|
10185
|
+
z20.literal(true).parse(record.retryQueued);
|
|
10186
|
+
z20.literal(positionals[2]).parse(record.notificationId);
|
|
10039
10187
|
} else if (route === "notifications destinations")
|
|
10040
|
-
|
|
10041
|
-
candidates:
|
|
10042
|
-
|
|
10043
|
-
candidateId:
|
|
10044
|
-
label:
|
|
10045
|
-
availability:
|
|
10188
|
+
z20.object({
|
|
10189
|
+
candidates: z20.array(
|
|
10190
|
+
z20.object({
|
|
10191
|
+
candidateId: z20.string(),
|
|
10192
|
+
label: z20.string(),
|
|
10193
|
+
availability: z20.literal("available")
|
|
10046
10194
|
})
|
|
10047
10195
|
)
|
|
10048
10196
|
}).parse(record);
|
|
@@ -10055,46 +10203,46 @@ async function runSeoCommand(options) {
|
|
|
10055
10203
|
notificationRoute.parse(record.route);
|
|
10056
10204
|
}
|
|
10057
10205
|
} else if (!writing) {
|
|
10058
|
-
const validated =
|
|
10059
|
-
resource:
|
|
10060
|
-
id:
|
|
10061
|
-
organizationId:
|
|
10206
|
+
const validated = z20.object({
|
|
10207
|
+
resource: z20.object({
|
|
10208
|
+
id: z20.literal(context.resourceId),
|
|
10209
|
+
organizationId: z20.literal(context.overview.project.organizationId)
|
|
10062
10210
|
}),
|
|
10063
|
-
audits:
|
|
10064
|
-
audit:
|
|
10065
|
-
id:
|
|
10066
|
-
resourceId:
|
|
10211
|
+
audits: z20.array(z20.object({ id: z20.string() }).passthrough()),
|
|
10212
|
+
audit: z20.object({
|
|
10213
|
+
id: z20.string(),
|
|
10214
|
+
resourceId: z20.literal(context.resourceId)
|
|
10067
10215
|
}).passthrough().nullable(),
|
|
10068
|
-
pages:
|
|
10069
|
-
issues:
|
|
10070
|
-
changes:
|
|
10071
|
-
totalChanges:
|
|
10072
|
-
dispositions:
|
|
10216
|
+
pages: z20.array(z20.unknown()),
|
|
10217
|
+
issues: z20.array(z20.unknown()),
|
|
10218
|
+
changes: z20.array(z20.unknown()),
|
|
10219
|
+
totalChanges: z20.number(),
|
|
10220
|
+
dispositions: z20.array(z20.unknown())
|
|
10073
10221
|
}).passthrough().parse(record);
|
|
10074
10222
|
const selected = query.get("audit");
|
|
10075
10223
|
if (selected && validated.audit?.id !== selected)
|
|
10076
10224
|
throw new Error("The SEO response does not match the requested audit.");
|
|
10077
10225
|
} else if (record.audit)
|
|
10078
|
-
|
|
10079
|
-
id:
|
|
10080
|
-
resourceId:
|
|
10081
|
-
organizationId:
|
|
10082
|
-
state:
|
|
10226
|
+
z20.object({
|
|
10227
|
+
id: z20.string(),
|
|
10228
|
+
resourceId: z20.literal(context.resourceId),
|
|
10229
|
+
organizationId: z20.literal(context.overview.project.organizationId),
|
|
10230
|
+
state: z20.literal("queued")
|
|
10083
10231
|
}).parse(record.audit);
|
|
10084
|
-
else if (route === "audit cancel")
|
|
10232
|
+
else if (route === "audit cancel") z20.literal(true).parse(record.cancelled);
|
|
10085
10233
|
else if (action === "issue")
|
|
10086
|
-
|
|
10087
|
-
url:
|
|
10088
|
-
ruleId:
|
|
10089
|
-
ignored:
|
|
10090
|
-
revision:
|
|
10234
|
+
z20.object({
|
|
10235
|
+
url: z20.literal(values.url),
|
|
10236
|
+
ruleId: z20.literal(values.rule),
|
|
10237
|
+
ignored: z20.literal(positionals[1] === "ignore"),
|
|
10238
|
+
revision: z20.literal(Number(values.revision) + 1)
|
|
10091
10239
|
}).parse(record.disposition);
|
|
10092
10240
|
else throw new Error("The SEO service returned an invalid response.");
|
|
10093
10241
|
return { exitCode: 0, stdout: JSON.stringify(record, null, 2) };
|
|
10094
10242
|
} catch (cause) {
|
|
10095
10243
|
const error = {
|
|
10096
10244
|
code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
|
|
10097
|
-
message: cause instanceof
|
|
10245
|
+
message: cause instanceof z20.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
|
|
10098
10246
|
};
|
|
10099
10247
|
return {
|
|
10100
10248
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|