@siteoshq/cli 1.6.0 → 1.8.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 +40 -1
- package/dist/cli.js +691 -181
- package/dist/cli.js.map +1 -1
- package/package.json +20 -21
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ __export(cookie_verification_exports, {
|
|
|
17
17
|
verificationTarget: () => verificationTarget,
|
|
18
18
|
verifyCookieWebsite: () => verifyCookieWebsite
|
|
19
19
|
});
|
|
20
|
-
import { z as
|
|
20
|
+
import { z as z15 } from "zod";
|
|
21
21
|
function verificationTarget(websiteUrl, candidate) {
|
|
22
22
|
const website = new URL(websiteUrl);
|
|
23
23
|
const target = new URL(candidate ?? websiteUrl, website);
|
|
@@ -362,73 +362,73 @@ var Names, Service, Envelope, State, VerificationInstallation;
|
|
|
362
362
|
var init_cookie_verification = __esm({
|
|
363
363
|
"src/services/cookie-verification.ts"() {
|
|
364
364
|
"use strict";
|
|
365
|
-
Names =
|
|
366
|
-
exact:
|
|
367
|
-
prefixes:
|
|
368
|
-
});
|
|
369
|
-
Service =
|
|
370
|
-
key:
|
|
371
|
-
purposeKey:
|
|
372
|
-
lifecycle:
|
|
373
|
-
scriptOrigins:
|
|
374
|
-
iframeOrigins:
|
|
375
|
-
pixelOrigins:
|
|
365
|
+
Names = z15.object({
|
|
366
|
+
exact: z15.array(z15.string()),
|
|
367
|
+
prefixes: z15.array(z15.string())
|
|
368
|
+
});
|
|
369
|
+
Service = z15.object({
|
|
370
|
+
key: z15.string(),
|
|
371
|
+
purposeKey: z15.string(),
|
|
372
|
+
lifecycle: z15.object({
|
|
373
|
+
scriptOrigins: z15.array(z15.string()),
|
|
374
|
+
iframeOrigins: z15.array(z15.string()),
|
|
375
|
+
pixelOrigins: z15.array(z15.string()),
|
|
376
376
|
firstPartyCookies: Names,
|
|
377
377
|
localStorage: Names
|
|
378
378
|
}).optional()
|
|
379
379
|
});
|
|
380
|
-
Envelope =
|
|
381
|
-
publicKey:
|
|
382
|
-
revision:
|
|
383
|
-
ruleKey:
|
|
384
|
-
profileKey:
|
|
385
|
-
trustedSignals:
|
|
386
|
-
region:
|
|
387
|
-
countryCode:
|
|
388
|
-
subdivisionCode:
|
|
380
|
+
Envelope = z15.object({
|
|
381
|
+
publicKey: z15.string(),
|
|
382
|
+
revision: z15.number(),
|
|
383
|
+
ruleKey: z15.string(),
|
|
384
|
+
profileKey: z15.string(),
|
|
385
|
+
trustedSignals: z15.object({
|
|
386
|
+
region: z15.object({
|
|
387
|
+
countryCode: z15.string().nullable(),
|
|
388
|
+
subdivisionCode: z15.string().nullable()
|
|
389
389
|
}).optional()
|
|
390
390
|
}).optional(),
|
|
391
|
-
config:
|
|
392
|
-
services:
|
|
393
|
-
categories:
|
|
394
|
-
integrations:
|
|
391
|
+
config: z15.object({
|
|
392
|
+
services: z15.array(Service),
|
|
393
|
+
categories: z15.array(z15.object({ key: z15.string(), required: z15.boolean() })),
|
|
394
|
+
integrations: z15.object({ googleConsentMode: z15.string() })
|
|
395
395
|
})
|
|
396
396
|
});
|
|
397
|
-
State =
|
|
398
|
-
runtimeVersion:
|
|
399
|
-
preview:
|
|
400
|
-
resolved:
|
|
401
|
-
publicKey:
|
|
402
|
-
revision:
|
|
403
|
-
ruleKey:
|
|
404
|
-
profileKey:
|
|
397
|
+
State = z15.object({
|
|
398
|
+
runtimeVersion: z15.string(),
|
|
399
|
+
preview: z15.boolean(),
|
|
400
|
+
resolved: z15.object({
|
|
401
|
+
publicKey: z15.string(),
|
|
402
|
+
revision: z15.number(),
|
|
403
|
+
ruleKey: z15.string(),
|
|
404
|
+
profileKey: z15.string()
|
|
405
405
|
}).nullable(),
|
|
406
|
-
consent:
|
|
407
|
-
categories:
|
|
408
|
-
decision:
|
|
409
|
-
globalPrivacyControl:
|
|
410
|
-
privacyChoices:
|
|
411
|
-
saleOrShareOptOut:
|
|
412
|
-
targetedAdvertisingOptOut:
|
|
406
|
+
consent: z15.object({
|
|
407
|
+
categories: z15.array(z15.string()),
|
|
408
|
+
decision: z15.string(),
|
|
409
|
+
globalPrivacyControl: z15.boolean(),
|
|
410
|
+
privacyChoices: z15.object({
|
|
411
|
+
saleOrShareOptOut: z15.boolean(),
|
|
412
|
+
targetedAdvertisingOptOut: z15.boolean()
|
|
413
413
|
})
|
|
414
414
|
}),
|
|
415
|
-
services:
|
|
416
|
-
|
|
417
|
-
key:
|
|
418
|
-
allowed:
|
|
419
|
-
footprintPresent:
|
|
415
|
+
services: z15.array(
|
|
416
|
+
z15.object({
|
|
417
|
+
key: z15.string(),
|
|
418
|
+
allowed: z15.boolean(),
|
|
419
|
+
footprintPresent: z15.boolean()
|
|
420
420
|
})
|
|
421
421
|
)
|
|
422
422
|
});
|
|
423
|
-
VerificationInstallation =
|
|
424
|
-
publicKey:
|
|
425
|
-
currentPublishedRevision:
|
|
426
|
-
delivery:
|
|
427
|
-
runtimeUrl:
|
|
428
|
-
configUrl:
|
|
429
|
-
analyticsUrl:
|
|
430
|
-
receiptsUrl:
|
|
431
|
-
handshakeUrl:
|
|
423
|
+
VerificationInstallation = z15.object({
|
|
424
|
+
publicKey: z15.string(),
|
|
425
|
+
currentPublishedRevision: z15.number().int().positive(),
|
|
426
|
+
delivery: z15.object({
|
|
427
|
+
runtimeUrl: z15.string().url(),
|
|
428
|
+
configUrl: z15.string().url(),
|
|
429
|
+
analyticsUrl: z15.string().url().nullable(),
|
|
430
|
+
receiptsUrl: z15.string().url(),
|
|
431
|
+
handshakeUrl: z15.string().url()
|
|
432
432
|
})
|
|
433
433
|
});
|
|
434
434
|
}
|
|
@@ -484,7 +484,8 @@ var siteOSServiceAudienceSchema = z.enum([
|
|
|
484
484
|
"siteos-forms",
|
|
485
485
|
"siteos-pulse",
|
|
486
486
|
"siteos-search",
|
|
487
|
-
"siteos-seo"
|
|
487
|
+
"siteos-seo",
|
|
488
|
+
"siteos-analytics"
|
|
488
489
|
]);
|
|
489
490
|
var siteOSServiceScopeSchema = z.string().min(1).max(160).regex(/^[a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*){2,}$/);
|
|
490
491
|
var scopeNamespaceByAudience = {
|
|
@@ -495,7 +496,8 @@ var scopeNamespaceByAudience = {
|
|
|
495
496
|
"siteos-forms": "forms",
|
|
496
497
|
"siteos-pulse": "pulse",
|
|
497
498
|
"siteos-search": "search",
|
|
498
|
-
"siteos-seo": "seo"
|
|
499
|
+
"siteos-seo": "seo",
|
|
500
|
+
"siteos-analytics": "analytics"
|
|
499
501
|
};
|
|
500
502
|
function matchingServiceScopes(value, context) {
|
|
501
503
|
const prefix = `${scopeNamespaceByAudience[value.audience]}:`;
|
|
@@ -1445,7 +1447,8 @@ var PROJECT_SERVICES = [
|
|
|
1445
1447
|
"forms",
|
|
1446
1448
|
"search",
|
|
1447
1449
|
"trace",
|
|
1448
|
-
"seo"
|
|
1450
|
+
"seo",
|
|
1451
|
+
"analytics"
|
|
1449
1452
|
];
|
|
1450
1453
|
var ProjectSchema = z4.object({
|
|
1451
1454
|
id: z4.string().min(1),
|
|
@@ -1499,7 +1502,7 @@ var OverviewSchema = z4.object({
|
|
|
1499
1502
|
});
|
|
1500
1503
|
function createProjectApi(input) {
|
|
1501
1504
|
const origin = resolveSiteOSAuthBaseUrl(input.env);
|
|
1502
|
-
async function request(
|
|
1505
|
+
async function request(path32, schema, body, method) {
|
|
1503
1506
|
const scope = body === void 0 ? "projects:workspace:read" : "projects:workspace:write";
|
|
1504
1507
|
const grant = await input.grants.acquire({
|
|
1505
1508
|
audience: "siteos-projects",
|
|
@@ -1513,7 +1516,7 @@ function createProjectApi(input) {
|
|
|
1513
1516
|
message: "SiteOS API access is unavailable."
|
|
1514
1517
|
});
|
|
1515
1518
|
const response = await input.fetchImpl(
|
|
1516
|
-
`${origin}/api/projects/v1/projects${
|
|
1519
|
+
`${origin}/api/projects/v1/projects${path32}`,
|
|
1517
1520
|
{
|
|
1518
1521
|
method: method ?? (body === void 0 ? "GET" : "POST"),
|
|
1519
1522
|
headers: {
|
|
@@ -1709,14 +1712,14 @@ async function commonServiceContext(options, service, environmentSlug) {
|
|
|
1709
1712
|
const binding = attachment.environments.find(
|
|
1710
1713
|
(item) => item.environmentId === context.environment.id
|
|
1711
1714
|
);
|
|
1712
|
-
if (["pulse", "cookie", "seo"].includes(service) && !binding)
|
|
1715
|
+
if (["pulse", "cookie", "seo", "analytics"].includes(service) && !binding)
|
|
1713
1716
|
throw new SiteOSAuthApiError({
|
|
1714
1717
|
code: "PROJECT_ENVIRONMENT_NOT_CONFIGURED",
|
|
1715
1718
|
message: `Set up ${service} in ${context.environment.name} with \`siteos project connect ${service}\`.`
|
|
1716
1719
|
});
|
|
1717
1720
|
return {
|
|
1718
1721
|
...context,
|
|
1719
|
-
resourceId: ["pulse", "cookie", "seo"].includes(service) ? binding.resourceId : attachment.resourceId,
|
|
1722
|
+
resourceId: ["pulse", "cookie", "seo", "analytics"].includes(service) ? binding.resourceId : attachment.resourceId,
|
|
1720
1723
|
environmentBinding: binding
|
|
1721
1724
|
};
|
|
1722
1725
|
}
|
|
@@ -3813,10 +3816,10 @@ async function runSubmissionsCommand(options) {
|
|
|
3813
3816
|
return usageError2(
|
|
3814
3817
|
"Use new, read, archived or spam for --status and --expected-status."
|
|
3815
3818
|
);
|
|
3816
|
-
const
|
|
3819
|
+
const filters2 = new URLSearchParams();
|
|
3817
3820
|
for (const key of ["query", "status", "from", "to", "limit", "cursor"]) {
|
|
3818
3821
|
const item = value(key);
|
|
3819
|
-
if (item)
|
|
3822
|
+
if (item) filters2.set(key, item);
|
|
3820
3823
|
}
|
|
3821
3824
|
const limit = Number(value("limit") ?? 50);
|
|
3822
3825
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
@@ -3853,7 +3856,7 @@ async function runSubmissionsCommand(options) {
|
|
|
3853
3856
|
environmentId: environment.id,
|
|
3854
3857
|
formId
|
|
3855
3858
|
};
|
|
3856
|
-
const response = action === "list" ? await context.client.listSubmissions({ ...input, filters }) : action === "read" ? await context.client.readSubmission({
|
|
3859
|
+
const response = action === "list" ? await context.client.listSubmissions({ ...input, filters: filters2 }) : action === "read" ? await context.client.readSubmission({
|
|
3857
3860
|
...input,
|
|
3858
3861
|
submissionId
|
|
3859
3862
|
}) : await context.client.updateSubmissionStatus({
|
|
@@ -9229,13 +9232,13 @@ Usage:
|
|
|
9229
9232
|
siteos project use <id-or-slug> [--json]
|
|
9230
9233
|
siteos project update [--name <name>] [--slug <slug>] [--url <production-url>] [--json]
|
|
9231
9234
|
siteos project status [--json]
|
|
9232
|
-
siteos project connect <pulse|cookie|forms|search|trace|seo> [--resource <id>] [--json]
|
|
9235
|
+
siteos project connect <pulse|cookie|forms|search|trace|seo|analytics> [--resource <id>] [--json]
|
|
9233
9236
|
siteos project environment list [--json]
|
|
9234
9237
|
siteos project environment create --name <name> --slug <slug> [--url <url>] [--json]
|
|
9235
9238
|
siteos project environment use <slug> [--json]
|
|
9236
9239
|
siteos project environment update <slug> [--name <name>] [--url <url>] [--json]
|
|
9237
|
-
siteos project environment resources <pulse|cookie|forms|search|trace|seo> [--json]
|
|
9238
|
-
siteos project environment connect <pulse|cookie|forms|search|trace|seo> --environment <slug> [--resource <id>] [--json]
|
|
9240
|
+
siteos project environment resources <pulse|cookie|forms|search|trace|seo|analytics> [--json]
|
|
9241
|
+
siteos project environment connect <pulse|cookie|forms|search|trace|seo|analytics> --environment <slug> [--resource <id>] [--json]
|
|
9239
9242
|
|
|
9240
9243
|
Select a Project once per repository. Service commands use its configured resources.
|
|
9241
9244
|
Connect creates a draft workspace, or explicitly attaches an existing resource.
|
|
@@ -9333,7 +9336,7 @@ Run \`siteos project status\` to inspect its services.`;
|
|
|
9333
9336
|
const service = parsed.positionals[0];
|
|
9334
9337
|
if (!PROJECT_SERVICES.includes(service))
|
|
9335
9338
|
throw new Error(
|
|
9336
|
-
"Choose pulse, cookie, forms, search, trace or
|
|
9339
|
+
"Choose pulse, cookie, forms, search, trace, seo or analytics. Organization connections use `siteos integrations`. "
|
|
9337
9340
|
);
|
|
9338
9341
|
overview = await api.connect(
|
|
9339
9342
|
overview.project.id,
|
|
@@ -9389,7 +9392,9 @@ async function runEnvironmentCommand3(options) {
|
|
|
9389
9392
|
throw new Error("Environment create requires --name and --slug.");
|
|
9390
9393
|
const service = positionals[0];
|
|
9391
9394
|
if ((action === "connect" || action === "resources") && !PROJECT_SERVICES.includes(service))
|
|
9392
|
-
throw new Error(
|
|
9395
|
+
throw new Error(
|
|
9396
|
+
"Choose pulse, cookie, forms, search, trace, seo or analytics."
|
|
9397
|
+
);
|
|
9393
9398
|
if (action === "connect" && !values.environment)
|
|
9394
9399
|
throw new Error("Choose a Project environment with --environment <slug>.");
|
|
9395
9400
|
const context = await readCommonProject(
|
|
@@ -9474,7 +9479,111 @@ async function runEnvironmentCommand3(options) {
|
|
|
9474
9479
|
import { readFile as readFile16, stat } from "fs/promises";
|
|
9475
9480
|
import path28 from "path";
|
|
9476
9481
|
import { parseArgs as parseArgs3 } from "util";
|
|
9477
|
-
import { z as
|
|
9482
|
+
import { z as z16 } from "zod";
|
|
9483
|
+
|
|
9484
|
+
// src/services/trace-explorer-command.ts
|
|
9485
|
+
import { z as z14 } from "zod";
|
|
9486
|
+
var filters = [
|
|
9487
|
+
"environment",
|
|
9488
|
+
"provider",
|
|
9489
|
+
"event",
|
|
9490
|
+
"property",
|
|
9491
|
+
"page-view",
|
|
9492
|
+
"search",
|
|
9493
|
+
"state",
|
|
9494
|
+
"rule",
|
|
9495
|
+
"kind",
|
|
9496
|
+
"period",
|
|
9497
|
+
"cursor"
|
|
9498
|
+
];
|
|
9499
|
+
var TRACE_EXPLORER_FLAGS = {
|
|
9500
|
+
destinations: filters,
|
|
9501
|
+
events: filters,
|
|
9502
|
+
properties: filters,
|
|
9503
|
+
issues: filters,
|
|
9504
|
+
observations: filters,
|
|
9505
|
+
"issue show": ["environment", "id", "cursor"],
|
|
9506
|
+
"observation show": ["environment", "batch-id", "event-id"]
|
|
9507
|
+
};
|
|
9508
|
+
var FilterValues = z14.object({
|
|
9509
|
+
provider: z14.enum([
|
|
9510
|
+
"siteos_analytics",
|
|
9511
|
+
"ga4",
|
|
9512
|
+
"google_ads",
|
|
9513
|
+
"hubspot",
|
|
9514
|
+
"meta",
|
|
9515
|
+
"custom"
|
|
9516
|
+
]).optional(),
|
|
9517
|
+
event: z14.string().min(1).max(160).optional(),
|
|
9518
|
+
property: z14.string().min(1).max(160).optional(),
|
|
9519
|
+
"page-view": z14.string().uuid().optional(),
|
|
9520
|
+
search: z14.string().max(160).optional(),
|
|
9521
|
+
state: z14.enum([
|
|
9522
|
+
"all",
|
|
9523
|
+
"active",
|
|
9524
|
+
"snoozed",
|
|
9525
|
+
"resolved",
|
|
9526
|
+
"new",
|
|
9527
|
+
"issues",
|
|
9528
|
+
"tracked",
|
|
9529
|
+
"ignored"
|
|
9530
|
+
]).optional(),
|
|
9531
|
+
rule: z14.string().min(1).max(80).optional(),
|
|
9532
|
+
kind: z14.enum([
|
|
9533
|
+
"data_layer",
|
|
9534
|
+
"fetch",
|
|
9535
|
+
"xhr",
|
|
9536
|
+
"beacon",
|
|
9537
|
+
"resource",
|
|
9538
|
+
"consent",
|
|
9539
|
+
"heartbeat",
|
|
9540
|
+
"runtime_diagnostic"
|
|
9541
|
+
]).optional(),
|
|
9542
|
+
period: z14.enum(["24h", "7d"]).optional(),
|
|
9543
|
+
cursor: z14.string().min(1).max(4096).optional()
|
|
9544
|
+
});
|
|
9545
|
+
function traceExplorerSuffix(route, values) {
|
|
9546
|
+
if (!TRACE_EXPLORER_FLAGS[route]) return null;
|
|
9547
|
+
const query = new URLSearchParams();
|
|
9548
|
+
if (route === "issue show" || route === "observation show") {
|
|
9549
|
+
const keys = route === "issue show" ? ["id"] : ["batch-id", "event-id"];
|
|
9550
|
+
for (const key of keys) {
|
|
9551
|
+
if (!z14.string().uuid().safeParse(values[key]).success)
|
|
9552
|
+
throw new Error(`Use --${key} with the UUID returned by Trace.`);
|
|
9553
|
+
}
|
|
9554
|
+
if (values.cursor !== void 0) {
|
|
9555
|
+
if (!z14.string().uuid().safeParse(values.cursor).success)
|
|
9556
|
+
throw new Error(
|
|
9557
|
+
"Use --cursor with the nextCursor returned by this issue."
|
|
9558
|
+
);
|
|
9559
|
+
query.set("cursor", values.cursor);
|
|
9560
|
+
}
|
|
9561
|
+
const suffix = route === "issue show" ? `/issues/${encodeURIComponent(values.id)}` : `/observations/${encodeURIComponent(values["batch-id"])}/${encodeURIComponent(values["event-id"])}`;
|
|
9562
|
+
return `${suffix}${query.size ? `?${query}` : ""}`;
|
|
9563
|
+
}
|
|
9564
|
+
const parsed = FilterValues.safeParse(values);
|
|
9565
|
+
if (!parsed.success) {
|
|
9566
|
+
const flag = parsed.error.issues[0]?.path[0];
|
|
9567
|
+
throw new Error(
|
|
9568
|
+
`Invalid --${String(flag)} filter. Run \`siteos trace --help\`.`
|
|
9569
|
+
);
|
|
9570
|
+
}
|
|
9571
|
+
for (const [key, value] of Object.entries(parsed.data)) {
|
|
9572
|
+
if (value !== void 0)
|
|
9573
|
+
query.set(key === "page-view" ? "pageView" : key, value);
|
|
9574
|
+
}
|
|
9575
|
+
return `/${route}${query.size ? `?${query}` : ""}`;
|
|
9576
|
+
}
|
|
9577
|
+
function tracePublicationVersion(value) {
|
|
9578
|
+
if (value === void 0) return void 0;
|
|
9579
|
+
if (!/^[1-9]\d*$/u.test(value) || !Number.isSafeInteger(Number(value)))
|
|
9580
|
+
throw new Error(
|
|
9581
|
+
"Use --expected-draft-version with a positive integer from the reviewed plan."
|
|
9582
|
+
);
|
|
9583
|
+
return Number(value);
|
|
9584
|
+
}
|
|
9585
|
+
|
|
9586
|
+
// src/services/service-command.ts
|
|
9478
9587
|
var SERVICE_HELP = {
|
|
9479
9588
|
cookie: `Manage Cookie for the selected SiteOS Project.
|
|
9480
9589
|
|
|
@@ -9501,12 +9610,27 @@ Usage:
|
|
|
9501
9610
|
siteos trace status [--json]
|
|
9502
9611
|
siteos trace environments [--json]
|
|
9503
9612
|
siteos trace report [--environment <slug>] [--json]
|
|
9613
|
+
siteos trace destinations [--environment <slug>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
9614
|
+
siteos trace events [--environment <slug>] [--provider <provider>] [--event <name>] [--search <text>] [--state <all|new|issues|tracked|ignored>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
9615
|
+
siteos trace properties [--environment <slug>] [--provider <provider>] [--event <name>] [--property <name>] [--search <text>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
9616
|
+
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]
|
|
9617
|
+
siteos trace observations [--environment <slug>] [--provider <provider>] [--event <name>] [--kind <kind>] [--page-view <uuid>] [--search <text>] [--period <24h|7d>] [--cursor <cursor>] [--json]
|
|
9618
|
+
siteos trace issue show --id <uuid> [--environment <slug>] [--cursor <finding-cursor>] [--json]
|
|
9619
|
+
siteos trace observation show --batch-id <uuid> --event-id <uuid> [--environment <slug>] [--json]
|
|
9504
9620
|
siteos trace installation <show|ensure|save|publish> [--environment <slug>] [--input <draft.json>] [--json]
|
|
9505
9621
|
siteos trace tracking-plan <show|ensure|save|publish> [--environment <slug>] [--input <plan.json>] [--json]
|
|
9622
|
+
siteos trace tracking-plan publish --expected-draft-version <number> [--environment <slug>] [--json]
|
|
9506
9623
|
|
|
9507
9624
|
Start with siteos project use, then siteos project connect trace.
|
|
9508
9625
|
Commands use the selected Project environment. Save requires --input with expectedDraftVersion.
|
|
9509
|
-
Ensure creates a draft; publish activates the reviewed configuration
|
|
9626
|
+
Ensure creates a draft; publish activates the reviewed configuration.
|
|
9627
|
+
Use --expected-draft-version when publishing a reviewed tracking plan; a conflict needs a fresh review.
|
|
9628
|
+
Explorer commands require the matching Trace server. They read one page and return nextCursor.
|
|
9629
|
+
Reuse the same filters with that cursor; omit it to start a fresh time window.
|
|
9630
|
+
Providers: siteos_analytics, ga4, google_ads, hubspot, meta, custom (data layer source).
|
|
9631
|
+
Kinds: data_layer, fetch, xhr, beacon, resource, consent, heartbeat, runtime_diagnostic.
|
|
9632
|
+
Lists also accept --provider, --event, --property, --page-view, --search, --state, --rule and --kind.
|
|
9633
|
+
Destinations are observed analytics services; a data layer event alone does not prove delivery.`,
|
|
9510
9634
|
integrations: `Manage shared Organization connections and notification destinations.
|
|
9511
9635
|
|
|
9512
9636
|
Usage:
|
|
@@ -9539,7 +9663,20 @@ async function runServiceCommand(service, options) {
|
|
|
9539
9663
|
subdivision: { type: "string" },
|
|
9540
9664
|
source: { type: "string" },
|
|
9541
9665
|
url: { type: "string" },
|
|
9542
|
-
browser: { type: "string" }
|
|
9666
|
+
browser: { type: "string" },
|
|
9667
|
+
provider: { type: "string" },
|
|
9668
|
+
event: { type: "string" },
|
|
9669
|
+
property: { type: "string" },
|
|
9670
|
+
"page-view": { type: "string" },
|
|
9671
|
+
search: { type: "string" },
|
|
9672
|
+
state: { type: "string" },
|
|
9673
|
+
rule: { type: "string" },
|
|
9674
|
+
kind: { type: "string" },
|
|
9675
|
+
period: { type: "string" },
|
|
9676
|
+
id: { type: "string" },
|
|
9677
|
+
"batch-id": { type: "string" },
|
|
9678
|
+
"event-id": { type: "string" },
|
|
9679
|
+
"expected-draft-version": { type: "string" }
|
|
9543
9680
|
}
|
|
9544
9681
|
});
|
|
9545
9682
|
const [action, subaction] = positionals;
|
|
@@ -9562,6 +9699,7 @@ async function runServiceCommand(service, options) {
|
|
|
9562
9699
|
status: [],
|
|
9563
9700
|
environments: [],
|
|
9564
9701
|
report: ["environment"],
|
|
9702
|
+
...TRACE_EXPLORER_FLAGS,
|
|
9565
9703
|
...Object.fromEntries(
|
|
9566
9704
|
["installation", "tracking-plan"].flatMap(
|
|
9567
9705
|
(section) => ["show", "ensure", "save", "publish"].map((operation) => [
|
|
@@ -9569,7 +9707,8 @@ async function runServiceCommand(service, options) {
|
|
|
9569
9707
|
operation === "save" ? ["environment", "input"] : ["environment"]
|
|
9570
9708
|
])
|
|
9571
9709
|
)
|
|
9572
|
-
)
|
|
9710
|
+
),
|
|
9711
|
+
"tracking-plan publish": ["environment", "expected-draft-version"]
|
|
9573
9712
|
},
|
|
9574
9713
|
integrations: {
|
|
9575
9714
|
status: [],
|
|
@@ -9593,6 +9732,10 @@ async function runServiceCommand(service, options) {
|
|
|
9593
9732
|
throw new Error(
|
|
9594
9733
|
"Destination creation requires --channel <provider-channel-id>."
|
|
9595
9734
|
);
|
|
9735
|
+
const explorerSuffix = service === "trace" ? traceExplorerSuffix(route, values) : null;
|
|
9736
|
+
const expectedDraftVersion = tracePublicationVersion(
|
|
9737
|
+
values["expected-draft-version"]
|
|
9738
|
+
);
|
|
9596
9739
|
const runtime = commonProjectRuntime(options);
|
|
9597
9740
|
const common = service === "integrations" ? null : await commonServiceContext(
|
|
9598
9741
|
options,
|
|
@@ -9632,8 +9775,8 @@ async function runServiceCommand(service, options) {
|
|
|
9632
9775
|
);
|
|
9633
9776
|
const result2 = await response.json();
|
|
9634
9777
|
if (!response.ok) {
|
|
9635
|
-
const error =
|
|
9636
|
-
error:
|
|
9778
|
+
const error = z16.object({
|
|
9779
|
+
error: z16.object({ code: z16.string(), message: z16.string().max(500) })
|
|
9637
9780
|
}).safeParse(result2);
|
|
9638
9781
|
throw new SiteOSAuthApiError({
|
|
9639
9782
|
code: error.success ? error.data.error.code : "SERVICE_REQUEST_FAILED",
|
|
@@ -9665,9 +9808,9 @@ async function runServiceCommand(service, options) {
|
|
|
9665
9808
|
await inputFile(),
|
|
9666
9809
|
"cookie:workspace:read"
|
|
9667
9810
|
);
|
|
9668
|
-
const validation =
|
|
9669
|
-
valid:
|
|
9670
|
-
draftVersionMatches:
|
|
9811
|
+
const validation = z16.object({
|
|
9812
|
+
valid: z16.boolean(),
|
|
9813
|
+
draftVersionMatches: z16.boolean().optional()
|
|
9671
9814
|
}).parse(result);
|
|
9672
9815
|
if (!validation.valid || validation.draftVersionMatches === false)
|
|
9673
9816
|
return { exitCode: 2, stdout: JSON.stringify(result, null, 2) };
|
|
@@ -9706,11 +9849,11 @@ async function runServiceCommand(service, options) {
|
|
|
9706
9849
|
} else if (action === "installation")
|
|
9707
9850
|
result = await request(`${site}/installation`);
|
|
9708
9851
|
else if (action === "draft" && subaction === "get" && positionals.length === 2) {
|
|
9709
|
-
const response =
|
|
9710
|
-
name:
|
|
9711
|
-
hostname:
|
|
9712
|
-
draftVersion:
|
|
9713
|
-
draft:
|
|
9852
|
+
const response = z16.object({
|
|
9853
|
+
name: z16.string(),
|
|
9854
|
+
hostname: z16.string(),
|
|
9855
|
+
draftVersion: z16.number(),
|
|
9856
|
+
draft: z16.unknown()
|
|
9714
9857
|
}).parse(await request(site));
|
|
9715
9858
|
result = {
|
|
9716
9859
|
name: response.name,
|
|
@@ -9741,10 +9884,10 @@ async function runServiceCommand(service, options) {
|
|
|
9741
9884
|
result = await request(site);
|
|
9742
9885
|
else if (action === "environments" && positionals.length === 1)
|
|
9743
9886
|
result = await request(`${site}/environments`);
|
|
9744
|
-
else if (action === "report" || action === "installation" || action === "tracking-plan") {
|
|
9745
|
-
const response =
|
|
9746
|
-
environments:
|
|
9747
|
-
|
|
9887
|
+
else if (action === "report" || action === "installation" || action === "tracking-plan" || explorerSuffix !== null) {
|
|
9888
|
+
const response = z16.object({
|
|
9889
|
+
environments: z16.array(
|
|
9890
|
+
z16.object({ id: z16.string(), slug: z16.string() })
|
|
9748
9891
|
)
|
|
9749
9892
|
}).parse(await request(`${site}/environments`));
|
|
9750
9893
|
const environment = common.overview.project.environments.find(
|
|
@@ -9768,12 +9911,14 @@ async function runServiceCommand(service, options) {
|
|
|
9768
9911
|
"Choose an environment from `siteos trace environments`."
|
|
9769
9912
|
);
|
|
9770
9913
|
const base = `/environments/${encodeURIComponent(matches[0].id)}`;
|
|
9771
|
-
if (
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
|
|
9914
|
+
if (explorerSuffix !== null) {
|
|
9915
|
+
result = await request(`${base}${explorerSuffix}`);
|
|
9916
|
+
} else if (action === "report" && positionals.length === 1) {
|
|
9917
|
+
const detail = z16.object({
|
|
9918
|
+
site: z16.object({
|
|
9919
|
+
id: z16.literal(common.resourceId),
|
|
9920
|
+
environments: z16.array(
|
|
9921
|
+
z16.object({ id: z16.string(), evidence: z16.unknown() })
|
|
9777
9922
|
)
|
|
9778
9923
|
})
|
|
9779
9924
|
}).parse(await request(site));
|
|
@@ -9795,7 +9940,7 @@ async function runServiceCommand(service, options) {
|
|
|
9795
9940
|
result = await request(
|
|
9796
9941
|
`${base}/${action}/${subaction}`,
|
|
9797
9942
|
"POST",
|
|
9798
|
-
{},
|
|
9943
|
+
expectedDraftVersion === void 0 ? {} : { expectedDraftVersion },
|
|
9799
9944
|
subaction === "publish" ? "trace:publication:write" : void 0
|
|
9800
9945
|
);
|
|
9801
9946
|
else
|
|
@@ -9831,24 +9976,381 @@ async function runServiceCommand(service, options) {
|
|
|
9831
9976
|
} catch (cause) {
|
|
9832
9977
|
return {
|
|
9833
9978
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
9834
|
-
stderr: cause instanceof SiteOSAuthApiError || !(cause instanceof
|
|
9979
|
+
stderr: cause instanceof SiteOSAuthApiError || !(cause instanceof z16.ZodError) && cause instanceof Error ? cause.message : "The service returned an invalid response."
|
|
9980
|
+
};
|
|
9981
|
+
}
|
|
9982
|
+
}
|
|
9983
|
+
|
|
9984
|
+
// src/services/analytics-command.ts
|
|
9985
|
+
import { readFile as readFile17, stat as stat2 } from "fs/promises";
|
|
9986
|
+
import path29 from "path";
|
|
9987
|
+
import { parseArgs as parseArgs4 } from "util";
|
|
9988
|
+
import { z as z17 } from "zod";
|
|
9989
|
+
var ANALYTICS_HELP = `Set up website Analytics in the selected Project environment.
|
|
9990
|
+
|
|
9991
|
+
Usage:
|
|
9992
|
+
siteos analytics status [--environment <slug>] [--json]
|
|
9993
|
+
siteos analytics installation [--environment <slug>] [--json]
|
|
9994
|
+
siteos analytics report [--days <1|7|28>] [--event <name>] [--country <ISO|unknown>] [--campaign <id>] [--environment <slug>] [--json]
|
|
9995
|
+
siteos analytics realtime [--country <ISO|unknown>] [--campaign <id>] [--environment <slug>] [--json]
|
|
9996
|
+
siteos analytics settings show [--environment <slug>] [--json]
|
|
9997
|
+
siteos analytics settings set --revision <number> [--enabled <true|false>] [--cookie-events <true|false>] [--minimal-realtime <true|false>] [--environment <slug>] [--json]
|
|
9998
|
+
siteos analytics events list [--environment <slug>] [--json]
|
|
9999
|
+
siteos analytics events create --file <event.json> [--environment <slug>] [--json]
|
|
10000
|
+
siteos analytics events snippet <name> [--environment <slug>] [--json]
|
|
10001
|
+
siteos analytics campaigns list [--environment <slug>] [--json]
|
|
10002
|
+
siteos analytics campaigns create --file <campaign.json> [--environment <slug>] [--json]
|
|
10003
|
+
siteos analytics goals list [--environment <slug>] [--json]
|
|
10004
|
+
siteos analytics goals create --file <goal.json> [--environment <slug>] [--json]
|
|
10005
|
+
siteos analytics goals archive <id> [--environment <slug>] [--json]
|
|
10006
|
+
siteos analytics funnels list [--environment <slug>] [--json]
|
|
10007
|
+
siteos analytics funnels create --file <funnel.json> [--environment <slug>] [--json]
|
|
10008
|
+
siteos analytics funnels archive <id> [--environment <slug>] [--json]
|
|
10009
|
+
siteos analytics monitoring prepare [--environment <slug>] [--json]
|
|
10010
|
+
|
|
10011
|
+
Connect first: siteos project connect analytics. Cookie and Trace are optional.
|
|
10012
|
+
Use project environment use <slug> to select an environment; no resource fallback is allowed.
|
|
10013
|
+
Analytics starts independently. Consent control is configured and published in Cookie.
|
|
10014
|
+
An external CMP can gate its loader explicitly; privacy opt-outs still apply.
|
|
10015
|
+
Settings require an owner/admin, the current revision and at least one change.
|
|
10016
|
+
Catalog files are bounded JSON using the documented event/campaign/goal/funnel contracts.
|
|
10017
|
+
Monitoring preparation creates a Trace draft only; publication remains a separate operation.
|
|
10018
|
+
Analytics is Unlimited during early access. No synthetic events are sent by these commands.`;
|
|
10019
|
+
var EventInput = z17.object({
|
|
10020
|
+
name: z17.string().regex(/^[a-z][a-z0-9_]{0,63}$/u).refine((v) => v !== "pageview" && !v.startsWith("cookie_")),
|
|
10021
|
+
label: z17.string().trim().min(1).max(80),
|
|
10022
|
+
properties: z17.record(
|
|
10023
|
+
z17.string().regex(/^[a-z][a-z0-9_]{0,39}$/u),
|
|
10024
|
+
z17.array(
|
|
10025
|
+
z17.string().min(1).max(80).regex(/^[a-zA-Z0-9 _./:-]+$/u)
|
|
10026
|
+
).min(1).max(20)
|
|
10027
|
+
).refine((v) => Object.keys(v).length <= 8)
|
|
10028
|
+
}).strict();
|
|
10029
|
+
var Resource = z17.object({
|
|
10030
|
+
id: z17.string(),
|
|
10031
|
+
organizationId: z17.string(),
|
|
10032
|
+
name: z17.string(),
|
|
10033
|
+
slug: z17.string(),
|
|
10034
|
+
origin: z17.string().url(),
|
|
10035
|
+
publicKey: z17.string(),
|
|
10036
|
+
revision: z17.number().int().positive(),
|
|
10037
|
+
enabled: z17.boolean(),
|
|
10038
|
+
cookieEvents: z17.boolean(),
|
|
10039
|
+
minimalRealtime: z17.boolean()
|
|
10040
|
+
});
|
|
10041
|
+
var readKeys = [
|
|
10042
|
+
"days",
|
|
10043
|
+
"from",
|
|
10044
|
+
"to",
|
|
10045
|
+
"totals",
|
|
10046
|
+
"trend",
|
|
10047
|
+
"pages",
|
|
10048
|
+
"sources",
|
|
10049
|
+
"countries",
|
|
10050
|
+
"countryDetectionConfigured",
|
|
10051
|
+
"countryFilter",
|
|
10052
|
+
"campaignFilter",
|
|
10053
|
+
"eventCounts",
|
|
10054
|
+
"recent",
|
|
10055
|
+
"lastReceivedAt",
|
|
10056
|
+
"campaigns",
|
|
10057
|
+
"goals",
|
|
10058
|
+
"funnels",
|
|
10059
|
+
"convertedVisits"
|
|
10060
|
+
];
|
|
10061
|
+
var liveKeys = [
|
|
10062
|
+
"at",
|
|
10063
|
+
"from",
|
|
10064
|
+
"activeSince",
|
|
10065
|
+
"collectionEnabled",
|
|
10066
|
+
"countryFilter",
|
|
10067
|
+
"campaignFilter",
|
|
10068
|
+
"activeVisitors",
|
|
10069
|
+
"visitors",
|
|
10070
|
+
"pageviews",
|
|
10071
|
+
"events",
|
|
10072
|
+
"trend",
|
|
10073
|
+
"pages",
|
|
10074
|
+
"sources",
|
|
10075
|
+
"countries",
|
|
10076
|
+
"eventCounts",
|
|
10077
|
+
"minimal"
|
|
10078
|
+
];
|
|
10079
|
+
var pick = (value, keys) => Object.fromEntries(
|
|
10080
|
+
keys.filter((key) => Object.hasOwn(value, key)).map((key) => [key, value[key]])
|
|
10081
|
+
);
|
|
10082
|
+
async function runAnalyticsCommand(options) {
|
|
10083
|
+
if (!options.args.length || options.args.some((v) => ["--help", "-h"].includes(v)))
|
|
10084
|
+
return { exitCode: 0, stdout: ANALYTICS_HELP };
|
|
10085
|
+
const json = options.args.includes("--json");
|
|
10086
|
+
try {
|
|
10087
|
+
const { positionals, values } = parseArgs4({
|
|
10088
|
+
args: options.args,
|
|
10089
|
+
strict: true,
|
|
10090
|
+
allowPositionals: true,
|
|
10091
|
+
options: {
|
|
10092
|
+
json: { type: "boolean" },
|
|
10093
|
+
environment: { type: "string" },
|
|
10094
|
+
days: { type: "string" },
|
|
10095
|
+
event: { type: "string" },
|
|
10096
|
+
country: { type: "string" },
|
|
10097
|
+
campaign: { type: "string" },
|
|
10098
|
+
revision: { type: "string" },
|
|
10099
|
+
enabled: { type: "string" },
|
|
10100
|
+
"cookie-events": { type: "string" },
|
|
10101
|
+
"minimal-realtime": { type: "string" },
|
|
10102
|
+
file: { type: "string" }
|
|
10103
|
+
}
|
|
10104
|
+
});
|
|
10105
|
+
const route = positionals.slice(0, 2).join(" "), action = positionals[0];
|
|
10106
|
+
const operations = {
|
|
10107
|
+
status: { args: 1, flags: [] },
|
|
10108
|
+
installation: { args: 1, flags: [] },
|
|
10109
|
+
report: { args: 1, flags: ["days", "event", "country", "campaign"] },
|
|
10110
|
+
realtime: { args: 1, flags: ["country", "campaign"] },
|
|
10111
|
+
"settings show": { args: 2, flags: [] },
|
|
10112
|
+
"settings set": {
|
|
10113
|
+
args: 2,
|
|
10114
|
+
flags: ["revision", "enabled", "cookie-events", "minimal-realtime"],
|
|
10115
|
+
scope: "analytics:workspace:write"
|
|
10116
|
+
},
|
|
10117
|
+
"events list": { args: 2, flags: [] },
|
|
10118
|
+
"events snippet": { args: 3, flags: [] },
|
|
10119
|
+
"events create": {
|
|
10120
|
+
args: 2,
|
|
10121
|
+
flags: ["file"],
|
|
10122
|
+
scope: "analytics:events:write"
|
|
10123
|
+
},
|
|
10124
|
+
"campaigns list": { args: 2, flags: [] },
|
|
10125
|
+
"campaigns create": {
|
|
10126
|
+
args: 2,
|
|
10127
|
+
flags: ["file"],
|
|
10128
|
+
scope: "analytics:reports:write"
|
|
10129
|
+
},
|
|
10130
|
+
"goals list": { args: 2, flags: [] },
|
|
10131
|
+
"goals create": {
|
|
10132
|
+
args: 2,
|
|
10133
|
+
flags: ["file"],
|
|
10134
|
+
scope: "analytics:reports:write"
|
|
10135
|
+
},
|
|
10136
|
+
"goals archive": { args: 3, flags: [], scope: "analytics:reports:write" },
|
|
10137
|
+
"funnels list": { args: 2, flags: [] },
|
|
10138
|
+
"funnels create": {
|
|
10139
|
+
args: 2,
|
|
10140
|
+
flags: ["file"],
|
|
10141
|
+
scope: "analytics:reports:write"
|
|
10142
|
+
},
|
|
10143
|
+
"funnels archive": {
|
|
10144
|
+
args: 3,
|
|
10145
|
+
flags: [],
|
|
10146
|
+
scope: "analytics:reports:write"
|
|
10147
|
+
},
|
|
10148
|
+
"monitoring prepare": {
|
|
10149
|
+
args: 2,
|
|
10150
|
+
flags: [],
|
|
10151
|
+
scope: "analytics:monitoring:write"
|
|
10152
|
+
}
|
|
10153
|
+
};
|
|
10154
|
+
const operation = operations[route];
|
|
10155
|
+
if (!operation || positionals.length !== operation.args || Object.keys(values).some(
|
|
10156
|
+
(key) => !["json", "environment", ...operation.flags].includes(key)
|
|
10157
|
+
))
|
|
10158
|
+
throw new Error(
|
|
10159
|
+
"Invalid Analytics operation or flags. Run `siteos analytics --help`."
|
|
10160
|
+
);
|
|
10161
|
+
if (values.days && !["1", "7", "28"].includes(values.days))
|
|
10162
|
+
throw new Error("Use --days 1, 7 or 28.");
|
|
10163
|
+
if (values.country && !/^(?:[A-Z]{2}|unknown)$/u.test(values.country))
|
|
10164
|
+
throw new Error("Use an uppercase ISO country code or unknown.");
|
|
10165
|
+
if (values.campaign) z17.string().uuid().parse(values.campaign);
|
|
10166
|
+
const setting = route === "settings set", creating = positionals[1] === "create", archive = positionals[1] === "archive";
|
|
10167
|
+
let body;
|
|
10168
|
+
if (setting) {
|
|
10169
|
+
if (!/^[1-9]\d{0,8}$/u.test(values.revision ?? ""))
|
|
10170
|
+
throw new Error(
|
|
10171
|
+
"Read settings first and supply the current positive --revision."
|
|
10172
|
+
);
|
|
10173
|
+
body = { revision: Number(values.revision) };
|
|
10174
|
+
for (const [flag, key] of [
|
|
10175
|
+
["enabled", "enabled"],
|
|
10176
|
+
["cookie-events", "cookieEvents"],
|
|
10177
|
+
["minimal-realtime", "minimalRealtime"]
|
|
10178
|
+
]) {
|
|
10179
|
+
if (values[flag] === void 0) continue;
|
|
10180
|
+
if (!["true", "false"].includes(values[flag]))
|
|
10181
|
+
throw new Error(`Use --${flag} true|false.`);
|
|
10182
|
+
body[key] = values[flag] === "true";
|
|
10183
|
+
}
|
|
10184
|
+
if (Object.keys(body).length < 2)
|
|
10185
|
+
throw new Error("Provide at least one setting to change.");
|
|
10186
|
+
} else if (creating) {
|
|
10187
|
+
if (!values.file)
|
|
10188
|
+
throw new Error("Creation requires --file with a JSON definition.");
|
|
10189
|
+
const filename = path29.resolve(options.cwd ?? process.cwd(), values.file);
|
|
10190
|
+
if ((await stat2(filename)).size > 16384)
|
|
10191
|
+
throw new Error("The definition must not exceed 16 KiB.");
|
|
10192
|
+
const text = await readFile17(filename, "utf8");
|
|
10193
|
+
if (Buffer.byteLength(text) > 16384)
|
|
10194
|
+
throw new Error("The definition must not exceed 16 KiB.");
|
|
10195
|
+
let definition;
|
|
10196
|
+
try {
|
|
10197
|
+
definition = JSON.parse(text);
|
|
10198
|
+
} catch {
|
|
10199
|
+
throw new Error("The definition must contain valid JSON.");
|
|
10200
|
+
}
|
|
10201
|
+
body = z17.record(z17.unknown()).parse(definition);
|
|
10202
|
+
if (action === "events") body = EventInput.parse(body);
|
|
10203
|
+
} else if (archive) body = { id: z17.string().uuid().parse(positionals[2]) };
|
|
10204
|
+
const context = await commonServiceContext(
|
|
10205
|
+
options,
|
|
10206
|
+
"analytics",
|
|
10207
|
+
values.environment
|
|
10208
|
+
);
|
|
10209
|
+
if (!context)
|
|
10210
|
+
throw new Error(
|
|
10211
|
+
"Select a SiteOS Project with `siteos project use` first."
|
|
10212
|
+
);
|
|
10213
|
+
const runtime = commonProjectRuntime(options), scope = operation.scope ?? "analytics:workspace:read";
|
|
10214
|
+
const grant = await runtime.grants.acquire({
|
|
10215
|
+
audience: "siteos-analytics",
|
|
10216
|
+
scopes: [scope]
|
|
10217
|
+
});
|
|
10218
|
+
if (grant.grant.audience !== "siteos-analytics" || grant.grant.scopes.length !== 1 || grant.grant.scopes[0] !== scope || grant.grant.organizationId !== context.overview.project.organizationId)
|
|
10219
|
+
throw new SiteOSAuthApiError({
|
|
10220
|
+
code: "AUTH_INVALID_RESPONSE",
|
|
10221
|
+
message: "The Analytics grant does not match this Project and operation."
|
|
10222
|
+
});
|
|
10223
|
+
const query = new URLSearchParams();
|
|
10224
|
+
for (const key of ["days", "event", "country", "campaign"])
|
|
10225
|
+
if (values[key]) query.set(key, values[key]);
|
|
10226
|
+
const suffix = action === "realtime" ? `/realtime?${query}` : setting ? "/settings" : creating || archive ? `/${action}` : route === "monitoring prepare" ? "/monitoring" : `?${query}`;
|
|
10227
|
+
if (!options.fetchImpl)
|
|
10228
|
+
throw new Error("SiteOS API access is unavailable.");
|
|
10229
|
+
const response = await options.fetchImpl(
|
|
10230
|
+
`${runtime.api.origin}/api/analytics/v1/resources/${encodeURIComponent(context.resourceId)}${suffix}`,
|
|
10231
|
+
{
|
|
10232
|
+
method: setting ? "PATCH" : archive ? "DELETE" : operation.scope ? "POST" : "GET",
|
|
10233
|
+
headers: {
|
|
10234
|
+
Accept: "application/json",
|
|
10235
|
+
Authorization: `Bearer ${grant.accessToken}`,
|
|
10236
|
+
...body ? { "Content-Type": "application/json" } : {}
|
|
10237
|
+
},
|
|
10238
|
+
...body ? { body: JSON.stringify(body) } : {},
|
|
10239
|
+
signal: AbortSignal.timeout(3e4)
|
|
10240
|
+
}
|
|
10241
|
+
);
|
|
10242
|
+
const value = await response.json();
|
|
10243
|
+
if (!response.ok) {
|
|
10244
|
+
const error = z17.object({
|
|
10245
|
+
error: z17.object({ code: z17.string(), message: z17.string().max(500) })
|
|
10246
|
+
}).safeParse(value);
|
|
10247
|
+
throw new SiteOSAuthApiError({
|
|
10248
|
+
code: error.success ? error.data.error.code : "ANALYTICS_REQUEST_FAILED",
|
|
10249
|
+
message: error.success ? error.data.error.message : "The Analytics request failed.",
|
|
10250
|
+
status: response.status
|
|
10251
|
+
});
|
|
10252
|
+
}
|
|
10253
|
+
const record = z17.object({
|
|
10254
|
+
contractVersion: z17.literal(1),
|
|
10255
|
+
resourceId: z17.literal(context.resourceId)
|
|
10256
|
+
}).passthrough().parse(value);
|
|
10257
|
+
let output;
|
|
10258
|
+
if (setting) {
|
|
10259
|
+
const saved = Resource.parse(record);
|
|
10260
|
+
if (saved.id !== context.resourceId || saved.organizationId !== context.overview.project.organizationId || saved.revision !== Number(values.revision) + 1 || Object.entries(body).some(
|
|
10261
|
+
([key, val]) => key !== "revision" && saved[key] !== val
|
|
10262
|
+
))
|
|
10263
|
+
throw new Error("The saved settings do not match this change.");
|
|
10264
|
+
output = saved;
|
|
10265
|
+
} else if (creating) {
|
|
10266
|
+
if (action === "events") {
|
|
10267
|
+
output = EventInput.parse(
|
|
10268
|
+
pick(record, ["name", "label", "properties"])
|
|
10269
|
+
);
|
|
10270
|
+
if (JSON.stringify(output) !== JSON.stringify(body))
|
|
10271
|
+
throw new Error("The saved event does not match this definition.");
|
|
10272
|
+
} else
|
|
10273
|
+
output = {
|
|
10274
|
+
id: z17.string().uuid().parse(record.id),
|
|
10275
|
+
...pick(
|
|
10276
|
+
record,
|
|
10277
|
+
action === "campaigns" ? ["label", "source", "medium", "campaign"] : action === "goals" ? ["label", "match"] : ["label", "steps"]
|
|
10278
|
+
)
|
|
10279
|
+
};
|
|
10280
|
+
} else if (archive)
|
|
10281
|
+
output = { archived: z17.literal(true).parse(record.archived) };
|
|
10282
|
+
else if (route === "monitoring prepare")
|
|
10283
|
+
output = { state: z17.literal("prepared").parse(record.state) };
|
|
10284
|
+
else if (action === "realtime") output = pick(record, liveKeys);
|
|
10285
|
+
else {
|
|
10286
|
+
const resource = Resource.parse(record.resource);
|
|
10287
|
+
if (resource.id !== context.resourceId || resource.organizationId !== context.overview.project.organizationId)
|
|
10288
|
+
throw new Error(
|
|
10289
|
+
"The Analytics response belongs to a different resource."
|
|
10290
|
+
);
|
|
10291
|
+
if (action === "status")
|
|
10292
|
+
output = {
|
|
10293
|
+
resource,
|
|
10294
|
+
lastReceivedAt: record.lastReceivedAt,
|
|
10295
|
+
consentSource: z17.object({
|
|
10296
|
+
consentSource: z17.enum([
|
|
10297
|
+
"cookie",
|
|
10298
|
+
"external",
|
|
10299
|
+
"waiting_for_cookie",
|
|
10300
|
+
"not_required"
|
|
10301
|
+
])
|
|
10302
|
+
}).parse(record.configuration).consentSource
|
|
10303
|
+
};
|
|
10304
|
+
else if (route === "settings show") output = resource;
|
|
10305
|
+
else if (action === "installation")
|
|
10306
|
+
output = {
|
|
10307
|
+
resource,
|
|
10308
|
+
installation: z17.string().parse(record.installation),
|
|
10309
|
+
configuration: record.configuration
|
|
10310
|
+
};
|
|
10311
|
+
else if (action === "events") {
|
|
10312
|
+
const definitions = z17.array(EventInput).parse(record.definitions);
|
|
10313
|
+
if (route === "events snippet") {
|
|
10314
|
+
const definition = definitions.find((d) => d.name === positionals[2]);
|
|
10315
|
+
if (!definition)
|
|
10316
|
+
throw new Error(
|
|
10317
|
+
"Create the event definition before requesting its snippet."
|
|
10318
|
+
);
|
|
10319
|
+
output = {
|
|
10320
|
+
name: definition.name,
|
|
10321
|
+
javascript: `window.SiteOSAnalytics?.track(${JSON.stringify(definition.name)}, ${JSON.stringify(Object.fromEntries(Object.entries(definition.properties).map(([key, values2]) => [key, values2[0]])))});`,
|
|
10322
|
+
guidance: "Trigger only after the business action succeeds; substitute declared categorical values."
|
|
10323
|
+
};
|
|
10324
|
+
} else output = { definitions, eventCounts: record.eventCounts };
|
|
10325
|
+
} else
|
|
10326
|
+
output = action === "report" ? pick(record, readKeys) : { [action]: z17.array(z17.unknown()).parse(record[action]) };
|
|
10327
|
+
}
|
|
10328
|
+
return { exitCode: 0, stdout: JSON.stringify(output, null, 2) };
|
|
10329
|
+
} catch (cause) {
|
|
10330
|
+
const error = cause instanceof SiteOSAuthApiError ? { code: cause.code, message: cause.message } : {
|
|
10331
|
+
code: "ANALYTICS_COMMAND_FAILED",
|
|
10332
|
+
message: cause instanceof z17.ZodError ? "The Analytics input or response does not match the supported contract." : cause instanceof Error ? cause.message : "The Analytics command failed."
|
|
10333
|
+
};
|
|
10334
|
+
return {
|
|
10335
|
+
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
10336
|
+
...json ? { stdout: JSON.stringify({ error }) } : { stderr: error.message }
|
|
9835
10337
|
};
|
|
9836
10338
|
}
|
|
9837
10339
|
}
|
|
9838
10340
|
|
|
9839
10341
|
// src/services/seo-command.ts
|
|
9840
10342
|
import { writeFile as writeFile9 } from "fs/promises";
|
|
9841
|
-
import
|
|
9842
|
-
import { parseArgs as
|
|
9843
|
-
import { z as
|
|
10343
|
+
import path31 from "path";
|
|
10344
|
+
import { parseArgs as parseArgs6 } from "util";
|
|
10345
|
+
import { z as z19 } from "zod";
|
|
9844
10346
|
|
|
9845
10347
|
// src/services/seo-performance-command.ts
|
|
9846
10348
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
9847
10349
|
import { writeFile as writeFile8 } from "fs/promises";
|
|
9848
|
-
import
|
|
10350
|
+
import path30 from "path";
|
|
9849
10351
|
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
9850
|
-
import { parseArgs as
|
|
9851
|
-
import { z as
|
|
10352
|
+
import { parseArgs as parseArgs5 } from "util";
|
|
10353
|
+
import { z as z18 } from "zod";
|
|
9852
10354
|
var PERFORMANCE_HELP = `
|
|
9853
10355
|
siteos seo performance run --audit <id> --url <url> [--url <url>...] [--device <mobile|desktop>] [--idempotency-key <key>] [--environment <slug>] [--json]
|
|
9854
10356
|
siteos seo performance list [--device <mobile|desktop>] [--environment <slug>] [--json]
|
|
@@ -9865,7 +10367,7 @@ Reuse the returned idempotency key after an uncertain run response. Wait default
|
|
|
9865
10367
|
async function runSeoPerformanceCommand(options) {
|
|
9866
10368
|
let idempotencyKey;
|
|
9867
10369
|
try {
|
|
9868
|
-
const { values, positionals } =
|
|
10370
|
+
const { values, positionals } = parseArgs5({
|
|
9869
10371
|
args: options.args.slice(1),
|
|
9870
10372
|
strict: true,
|
|
9871
10373
|
allowPositionals: true,
|
|
@@ -9936,12 +10438,12 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9936
10438
|
const runtime = commonProjectRuntime(options);
|
|
9937
10439
|
const writing = ["run", "cancel"].includes(action);
|
|
9938
10440
|
const scope = writing ? "seo:audits:write" : "seo:workspace:read";
|
|
9939
|
-
const batchSchema =
|
|
9940
|
-
id:
|
|
9941
|
-
resourceId:
|
|
9942
|
-
organizationId:
|
|
9943
|
-
sourceAuditId:
|
|
9944
|
-
state:
|
|
10441
|
+
const batchSchema = z18.object({
|
|
10442
|
+
id: z18.string(),
|
|
10443
|
+
resourceId: z18.literal(context.resourceId),
|
|
10444
|
+
organizationId: z18.literal(context.overview.project.organizationId),
|
|
10445
|
+
sourceAuditId: z18.string(),
|
|
10446
|
+
state: z18.enum([
|
|
9945
10447
|
"queued",
|
|
9946
10448
|
"running",
|
|
9947
10449
|
"completed",
|
|
@@ -9949,8 +10451,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9949
10451
|
"failed",
|
|
9950
10452
|
"cancelled"
|
|
9951
10453
|
]),
|
|
9952
|
-
device:
|
|
9953
|
-
urls:
|
|
10454
|
+
device: z18.enum(["mobile", "desktop"]),
|
|
10455
|
+
urls: z18.array(z18.string()).min(1).max(10)
|
|
9954
10456
|
}).passthrough();
|
|
9955
10457
|
const query = new URLSearchParams();
|
|
9956
10458
|
if (values.device) query.set("device", values.device);
|
|
@@ -9998,17 +10500,17 @@ async function runSeoPerformanceCommand(options) {
|
|
|
9998
10500
|
);
|
|
9999
10501
|
const text = await response.text();
|
|
10000
10502
|
if (values.format === "json") {
|
|
10001
|
-
const parsed =
|
|
10002
|
-
contractVersion:
|
|
10503
|
+
const parsed = z18.object({
|
|
10504
|
+
contractVersion: z18.literal(1),
|
|
10003
10505
|
batch: batchSchema,
|
|
10004
|
-
pages:
|
|
10506
|
+
pages: z18.array(z18.unknown())
|
|
10005
10507
|
}).parse(JSON.parse(text));
|
|
10006
10508
|
if (parsed.batch.id !== id)
|
|
10007
10509
|
throw new Error(
|
|
10008
10510
|
"The export response does not match the selected check."
|
|
10009
10511
|
);
|
|
10010
10512
|
}
|
|
10011
|
-
const output =
|
|
10513
|
+
const output = path30.resolve(
|
|
10012
10514
|
options.cwd ?? process.cwd(),
|
|
10013
10515
|
values.output
|
|
10014
10516
|
);
|
|
@@ -10024,8 +10526,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
10024
10526
|
}
|
|
10025
10527
|
const data = await response.json();
|
|
10026
10528
|
if (!response.ok) {
|
|
10027
|
-
const error =
|
|
10028
|
-
error:
|
|
10529
|
+
const error = z18.object({
|
|
10530
|
+
error: z18.object({ code: z18.string(), message: z18.string().max(500) })
|
|
10029
10531
|
}).safeParse(data);
|
|
10030
10532
|
throw new SiteOSAuthApiError({
|
|
10031
10533
|
code: error.success ? error.data.error.code : "SEO_REQUEST_FAILED",
|
|
@@ -10033,8 +10535,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
10033
10535
|
status: response.status
|
|
10034
10536
|
});
|
|
10035
10537
|
}
|
|
10036
|
-
const record =
|
|
10037
|
-
if (action === "cancel")
|
|
10538
|
+
const record = z18.object({ contractVersion: z18.literal(1) }).passthrough().parse(data);
|
|
10539
|
+
if (action === "cancel") z18.literal(true).parse(record.cancelled);
|
|
10038
10540
|
else if (action === "run") {
|
|
10039
10541
|
const accepted = batchSchema.parse(record.batch);
|
|
10040
10542
|
const normalize = (url) => {
|
|
@@ -10047,8 +10549,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
10047
10549
|
"The queued check does not match the requested source, device and URLs."
|
|
10048
10550
|
);
|
|
10049
10551
|
} else {
|
|
10050
|
-
|
|
10051
|
-
|
|
10552
|
+
z18.literal(context.resourceId).parse(record.resourceId);
|
|
10553
|
+
z18.array(batchSchema).parse(record.batches);
|
|
10052
10554
|
const selected = batchSchema.nullable().parse(record.batch);
|
|
10053
10555
|
if (id && selected?.id !== id)
|
|
10054
10556
|
throw new Error(
|
|
@@ -10075,7 +10577,7 @@ async function runSeoPerformanceCommand(options) {
|
|
|
10075
10577
|
} catch (cause) {
|
|
10076
10578
|
const error = {
|
|
10077
10579
|
code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
|
|
10078
|
-
message: cause instanceof
|
|
10580
|
+
message: cause instanceof z18.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The performance command failed."
|
|
10079
10581
|
};
|
|
10080
10582
|
return {
|
|
10081
10583
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
@@ -10128,7 +10630,7 @@ async function runSeoCommand(options) {
|
|
|
10128
10630
|
return runSeoPerformanceCommand(options);
|
|
10129
10631
|
const json = options.args.includes("--json");
|
|
10130
10632
|
try {
|
|
10131
|
-
const { positionals, values } =
|
|
10633
|
+
const { positionals, values } = parseArgs6({
|
|
10132
10634
|
args: options.args,
|
|
10133
10635
|
strict: true,
|
|
10134
10636
|
allowPositionals: true,
|
|
@@ -10341,17 +10843,17 @@ async function runSeoCommand(options) {
|
|
|
10341
10843
|
);
|
|
10342
10844
|
const text = await response.text();
|
|
10343
10845
|
if (values.format === "json")
|
|
10344
|
-
|
|
10345
|
-
contractVersion:
|
|
10346
|
-
audit:
|
|
10347
|
-
id:
|
|
10348
|
-
resourceId:
|
|
10846
|
+
z19.object({
|
|
10847
|
+
contractVersion: z19.literal(1),
|
|
10848
|
+
audit: z19.object({
|
|
10849
|
+
id: z19.literal(values.audit),
|
|
10850
|
+
resourceId: z19.literal(context.resourceId)
|
|
10349
10851
|
}),
|
|
10350
|
-
kind:
|
|
10351
|
-
totalRows:
|
|
10352
|
-
rows:
|
|
10852
|
+
kind: z19.literal(values.kind),
|
|
10853
|
+
totalRows: z19.literal(rows),
|
|
10854
|
+
rows: z19.array(z19.unknown()).length(rows)
|
|
10353
10855
|
}).parse(JSON.parse(text));
|
|
10354
|
-
const output =
|
|
10856
|
+
const output = path31.resolve(options.cwd ?? process.cwd(), values.output);
|
|
10355
10857
|
await writeFile9(output, text, { flag: "wx", mode: 384 });
|
|
10356
10858
|
return {
|
|
10357
10859
|
exitCode: 0,
|
|
@@ -10370,8 +10872,8 @@ async function runSeoCommand(options) {
|
|
|
10370
10872
|
}
|
|
10371
10873
|
const data = await response.json();
|
|
10372
10874
|
if (!response.ok) {
|
|
10373
|
-
const result =
|
|
10374
|
-
error:
|
|
10875
|
+
const result = z19.object({
|
|
10876
|
+
error: z19.object({ code: z19.string(), message: z19.string().max(500) })
|
|
10375
10877
|
}).safeParse(data);
|
|
10376
10878
|
throw new SiteOSAuthApiError({
|
|
10377
10879
|
code: result.success ? result.data.error.code : "SEO_REQUEST_FAILED",
|
|
@@ -10379,34 +10881,34 @@ async function runSeoCommand(options) {
|
|
|
10379
10881
|
status: response.status
|
|
10380
10882
|
});
|
|
10381
10883
|
}
|
|
10382
|
-
const record =
|
|
10884
|
+
const record = z19.object({ contractVersion: z19.literal(1) }).passthrough().parse(data);
|
|
10383
10885
|
if (automation) {
|
|
10384
|
-
|
|
10385
|
-
const schedule =
|
|
10386
|
-
enabled:
|
|
10387
|
-
weekday:
|
|
10388
|
-
time:
|
|
10389
|
-
timeZone:
|
|
10390
|
-
revision:
|
|
10391
|
-
nextRunAt:
|
|
10886
|
+
z19.literal(context.resourceId).parse(record.resourceId);
|
|
10887
|
+
const schedule = z19.object({
|
|
10888
|
+
enabled: z19.boolean(),
|
|
10889
|
+
weekday: z19.number().int().min(1).max(7),
|
|
10890
|
+
time: z19.string(),
|
|
10891
|
+
timeZone: z19.string(),
|
|
10892
|
+
revision: z19.number().int().min(0),
|
|
10893
|
+
nextRunAt: z19.string().nullable()
|
|
10392
10894
|
});
|
|
10393
|
-
const notificationRoute =
|
|
10394
|
-
enabled:
|
|
10395
|
-
minimumSeverity:
|
|
10396
|
-
includeFailures:
|
|
10397
|
-
revision:
|
|
10398
|
-
destinationId:
|
|
10895
|
+
const notificationRoute = z19.object({
|
|
10896
|
+
enabled: z19.boolean(),
|
|
10897
|
+
minimumSeverity: z19.enum(["error", "warning"]),
|
|
10898
|
+
includeFailures: z19.boolean(),
|
|
10899
|
+
revision: z19.number().int().min(0),
|
|
10900
|
+
destinationId: z19.string().nullable()
|
|
10399
10901
|
});
|
|
10400
10902
|
if (retryNotification) {
|
|
10401
|
-
|
|
10402
|
-
|
|
10903
|
+
z19.literal(true).parse(record.retryQueued);
|
|
10904
|
+
z19.literal(positionals[2]).parse(record.notificationId);
|
|
10403
10905
|
} else if (route === "notifications destinations")
|
|
10404
|
-
|
|
10405
|
-
candidates:
|
|
10406
|
-
|
|
10407
|
-
candidateId:
|
|
10408
|
-
label:
|
|
10409
|
-
availability:
|
|
10906
|
+
z19.object({
|
|
10907
|
+
candidates: z19.array(
|
|
10908
|
+
z19.object({
|
|
10909
|
+
candidateId: z19.string(),
|
|
10910
|
+
label: z19.string(),
|
|
10911
|
+
availability: z19.literal("available")
|
|
10410
10912
|
})
|
|
10411
10913
|
)
|
|
10412
10914
|
}).parse(record);
|
|
@@ -10419,46 +10921,46 @@ async function runSeoCommand(options) {
|
|
|
10419
10921
|
notificationRoute.parse(record.route);
|
|
10420
10922
|
}
|
|
10421
10923
|
} else if (!writing) {
|
|
10422
|
-
const validated =
|
|
10423
|
-
resource:
|
|
10424
|
-
id:
|
|
10425
|
-
organizationId:
|
|
10924
|
+
const validated = z19.object({
|
|
10925
|
+
resource: z19.object({
|
|
10926
|
+
id: z19.literal(context.resourceId),
|
|
10927
|
+
organizationId: z19.literal(context.overview.project.organizationId)
|
|
10426
10928
|
}),
|
|
10427
|
-
audits:
|
|
10428
|
-
audit:
|
|
10429
|
-
id:
|
|
10430
|
-
resourceId:
|
|
10929
|
+
audits: z19.array(z19.object({ id: z19.string() }).passthrough()),
|
|
10930
|
+
audit: z19.object({
|
|
10931
|
+
id: z19.string(),
|
|
10932
|
+
resourceId: z19.literal(context.resourceId)
|
|
10431
10933
|
}).passthrough().nullable(),
|
|
10432
|
-
pages:
|
|
10433
|
-
issues:
|
|
10434
|
-
changes:
|
|
10435
|
-
totalChanges:
|
|
10436
|
-
dispositions:
|
|
10934
|
+
pages: z19.array(z19.unknown()),
|
|
10935
|
+
issues: z19.array(z19.unknown()),
|
|
10936
|
+
changes: z19.array(z19.unknown()),
|
|
10937
|
+
totalChanges: z19.number(),
|
|
10938
|
+
dispositions: z19.array(z19.unknown())
|
|
10437
10939
|
}).passthrough().parse(record);
|
|
10438
10940
|
const selected = query.get("audit");
|
|
10439
10941
|
if (selected && validated.audit?.id !== selected)
|
|
10440
10942
|
throw new Error("The SEO response does not match the requested audit.");
|
|
10441
10943
|
} else if (record.audit)
|
|
10442
|
-
|
|
10443
|
-
id:
|
|
10444
|
-
resourceId:
|
|
10445
|
-
organizationId:
|
|
10446
|
-
state:
|
|
10944
|
+
z19.object({
|
|
10945
|
+
id: z19.string(),
|
|
10946
|
+
resourceId: z19.literal(context.resourceId),
|
|
10947
|
+
organizationId: z19.literal(context.overview.project.organizationId),
|
|
10948
|
+
state: z19.literal("queued")
|
|
10447
10949
|
}).parse(record.audit);
|
|
10448
|
-
else if (route === "audit cancel")
|
|
10950
|
+
else if (route === "audit cancel") z19.literal(true).parse(record.cancelled);
|
|
10449
10951
|
else if (action === "issue")
|
|
10450
|
-
|
|
10451
|
-
url:
|
|
10452
|
-
ruleId:
|
|
10453
|
-
ignored:
|
|
10454
|
-
revision:
|
|
10952
|
+
z19.object({
|
|
10953
|
+
url: z19.literal(values.url),
|
|
10954
|
+
ruleId: z19.literal(values.rule),
|
|
10955
|
+
ignored: z19.literal(positionals[1] === "ignore"),
|
|
10956
|
+
revision: z19.literal(Number(values.revision) + 1)
|
|
10455
10957
|
}).parse(record.disposition);
|
|
10456
10958
|
else throw new Error("The SEO service returned an invalid response.");
|
|
10457
10959
|
return { exitCode: 0, stdout: JSON.stringify(record, null, 2) };
|
|
10458
10960
|
} catch (cause) {
|
|
10459
10961
|
const error = {
|
|
10460
10962
|
code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
|
|
10461
|
-
message: cause instanceof
|
|
10963
|
+
message: cause instanceof z19.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
|
|
10462
10964
|
};
|
|
10463
10965
|
return {
|
|
10464
10966
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
@@ -10500,6 +11002,12 @@ if (!command || command === "--help" || command === "-h") {
|
|
|
10500
11002
|
}
|
|
10501
11003
|
function rootCommandRegistry() {
|
|
10502
11004
|
return createCommandRegistry({
|
|
11005
|
+
analytics: (args2) => runAnalyticsCommand({
|
|
11006
|
+
args: args2,
|
|
11007
|
+
cwd: process.cwd(),
|
|
11008
|
+
env: process.env,
|
|
11009
|
+
fetchImpl: globalThis.fetch
|
|
11010
|
+
}),
|
|
10503
11011
|
seo: (args2) => runSeoCommand({
|
|
10504
11012
|
args: args2,
|
|
10505
11013
|
cwd: process.cwd(),
|
|
@@ -10613,6 +11121,7 @@ Usage:
|
|
|
10613
11121
|
siteos project --help
|
|
10614
11122
|
siteos cookie --help
|
|
10615
11123
|
siteos trace --help
|
|
11124
|
+
siteos analytics --help
|
|
10616
11125
|
siteos seo --help
|
|
10617
11126
|
siteos integrations --help
|
|
10618
11127
|
siteos pulse --help
|
|
@@ -10625,6 +11134,7 @@ Commands:
|
|
|
10625
11134
|
project Select one Project and configure its services and environments.
|
|
10626
11135
|
cookie Configure, publish, and inspect the Project\u2019s cookie banner.
|
|
10627
11136
|
trace Configure analytics observation and inspect evidence.
|
|
11137
|
+
analytics Configure website Analytics, events and realtime reports.
|
|
10628
11138
|
seo Audit HTML, inspect changes and verify fixes.
|
|
10629
11139
|
integrations Manage Organization connections and destinations.
|
|
10630
11140
|
pulse Manage monitoring checks, tests, and deployments.
|