@canonry/canonry 4.158.0 → 4.160.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 +3 -3
- package/THIRD_PARTY_NOTICES.md +102 -0
- package/assets/THIRD_PARTY_NOTICES.md +102 -0
- package/assets/agent-workspace/skills/aero/SKILL.md +16 -1
- package/assets/agent-workspace/skills/canonry/SKILL.md +17 -5
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +67 -0
- package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +231 -62
- package/assets/assets/{AuditHistoryPanel-McQfjoU9.js → AuditHistoryPanel-AtgoG2AH.js} +1 -1
- package/assets/assets/{BacklinksPage-Da8y1Wv8.js → BacklinksPage-DrOSF7Mu.js} +1 -1
- package/assets/assets/{HistoryPage-9MJfhRyT.js → HistoryPage-CGQXleJc.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-BiNAHEJW.js → MeasurementPropertyPage-C7D2OgIQ.js} +1 -1
- package/assets/assets/ProjectPage-Lp1VjNvL.js +12 -0
- package/assets/assets/{RunRow-DCG2LBlS.js → RunRow-BdzKKODo.js} +1 -1
- package/assets/assets/{RunsPage-ByWA_FSk.js → RunsPage-BU96L07S.js} +1 -1
- package/assets/assets/{SettingsPage-DdSeKAKF.js → SettingsPage-LEca0kDH.js} +1 -1
- package/assets/assets/SiteHealthSection-CKM4DUfE.js +4 -0
- package/assets/assets/{TrafficPage-5u8rPcBt.js → TrafficPage-tU9wl1F_.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-Dm-fK87u.js → TrafficSourceDetailPage-DZTpnU9f.js} +1 -1
- package/assets/assets/extract-error-message-BAyN-ftk.js +1 -0
- package/assets/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/assets/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/assets/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/assets/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/assets/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/assets/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/assets/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/assets/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/assets/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/assets/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/assets/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/assets/assets/index-CACRaOmZ.css +1 -0
- package/assets/assets/index-Wqv7kvs-.js +83 -0
- package/assets/assets/{react-sigma_core.esm.min-ComIyDKi.js → react-sigma_core.esm.min-DlZOAc_w.js} +2 -2
- package/assets/assets/{vendor-lucide-BtYdosYk.js → vendor-lucide-nYKv-BB7.js} +1 -1
- package/assets/assets/{vendor-markdown-D274_wsI.js → vendor-markdown-Bn7fRwrx.js} +1 -1
- package/assets/assets/{vendor-radix-BxMXSwbC.js → vendor-radix-4UOaVWza.js} +1 -1
- package/assets/assets/{vendor-recharts-C4ktw_aE.js → vendor-recharts-D8rt5lKn.js} +1 -1
- package/assets/assets/{vendor-tanstack-pFxw0eGP.js → vendor-tanstack-Dock0eH1.js} +1 -1
- package/assets/index.html +7 -7
- package/dist/{chunk-DEVAEC2S.js → chunk-7M7T5QXS.js} +290 -16
- package/dist/{chunk-LK6YFHG4.js → chunk-HQAVEK42.js} +65 -15
- package/dist/{chunk-YP4K2KXH.js → chunk-X7CYY5Q7.js} +2687 -686
- package/dist/{chunk-4VZP64GZ.js → chunk-XGESWHFP.js} +660 -274
- package/dist/cli.js +333 -117
- package/dist/index.d.ts +37 -14
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-LQ6ZRWMF.js → intelligence-service-6XQMM466.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +11 -9
- package/assets/assets/ProjectPage-mWSMjXrR.js +0 -15
- package/assets/assets/extract-error-message-CtxkAd6E.js +0 -1
- package/assets/assets/index-DUfg50Pl.js +0 -83
- package/assets/assets/index-cXb3mfeQ.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
detectAndTrackUpgrade,
|
|
17
17
|
emitInstallSummary,
|
|
18
18
|
formatAuditFactorScore,
|
|
19
|
-
|
|
19
|
+
getCloudflareTrafficConnectionBySourceId,
|
|
20
20
|
getMissingUserSkillsNudge,
|
|
21
21
|
getOrCreateAnonymousId,
|
|
22
22
|
installSkills,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
showFirstRunNotice,
|
|
32
32
|
trackCliCommandFinished,
|
|
33
33
|
trackEvent
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-XGESWHFP.js";
|
|
35
35
|
import {
|
|
36
36
|
CliError,
|
|
37
37
|
EXIT_SYSTEM_ERROR,
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
saveConfigPatch,
|
|
52
52
|
systemError,
|
|
53
53
|
usageError
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-HQAVEK42.js";
|
|
55
55
|
import {
|
|
56
56
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
57
57
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
projects,
|
|
66
66
|
queries,
|
|
67
67
|
renderReportHtml
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-X7CYY5Q7.js";
|
|
69
69
|
import {
|
|
70
70
|
AdsDeliverySnapshotStatuses,
|
|
71
71
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -129,7 +129,7 @@ import {
|
|
|
129
129
|
providerQuotaPolicySchema,
|
|
130
130
|
resolveProviderInput,
|
|
131
131
|
winnabilityClassSchema
|
|
132
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-7M7T5QXS.js";
|
|
133
133
|
|
|
134
134
|
// src/cli.ts
|
|
135
135
|
import { pathToFileURL } from "url";
|
|
@@ -3875,9 +3875,9 @@ async function gaConnect(project, opts) {
|
|
|
3875
3875
|
propertyId: opts.propertyId
|
|
3876
3876
|
};
|
|
3877
3877
|
if (opts.keyFile) {
|
|
3878
|
-
const
|
|
3878
|
+
const fs19 = await import("fs");
|
|
3879
3879
|
try {
|
|
3880
|
-
const content =
|
|
3880
|
+
const content = fs19.readFileSync(opts.keyFile, "utf-8");
|
|
3881
3881
|
JSON.parse(content);
|
|
3882
3882
|
body.keyJson = content;
|
|
3883
3883
|
} catch (e) {
|
|
@@ -5292,6 +5292,9 @@ var GET_CLI_COMMANDS = [
|
|
|
5292
5292
|
}
|
|
5293
5293
|
];
|
|
5294
5294
|
|
|
5295
|
+
// src/commands/traffic.ts
|
|
5296
|
+
import fs5 from "fs";
|
|
5297
|
+
|
|
5295
5298
|
// src/cloudflare-worker-deploy.ts
|
|
5296
5299
|
import { spawn } from "child_process";
|
|
5297
5300
|
import { randomUUID } from "crypto";
|
|
@@ -5455,7 +5458,8 @@ function writeCloudflareWorkerArtifacts(artifacts, contents) {
|
|
|
5455
5458
|
}
|
|
5456
5459
|
function assertCloudflareArtifactsDoNotContainSecrets(contents, secrets) {
|
|
5457
5460
|
const artifactText = [contents.workerScript, contents.wranglerToml, contents.instructions ?? ""];
|
|
5458
|
-
|
|
5461
|
+
const secretValues = "apiToken" in secrets ? [secrets.apiToken] : [secrets.bearerToken, secrets.hmacSecret];
|
|
5462
|
+
for (const secret of secretValues) {
|
|
5459
5463
|
if (secret && artifactText.some((value) => value.includes(secret))) {
|
|
5460
5464
|
throw new Error("Cloudflare setup response unexpectedly contained a cleartext secret");
|
|
5461
5465
|
}
|
|
@@ -5463,7 +5467,8 @@ function assertCloudflareArtifactsDoNotContainSecrets(contents, secrets) {
|
|
|
5463
5467
|
}
|
|
5464
5468
|
function redactCloudflareSecrets(message, secrets) {
|
|
5465
5469
|
let redacted = message;
|
|
5466
|
-
|
|
5470
|
+
const secretValues = "apiToken" in secrets ? [secrets.apiToken] : [secrets.bearerToken, secrets.hmacSecret];
|
|
5471
|
+
for (const secret of secretValues) {
|
|
5467
5472
|
if (secret) redacted = redacted.replaceAll(secret, "[REDACTED]");
|
|
5468
5473
|
}
|
|
5469
5474
|
return redacted;
|
|
@@ -5520,12 +5525,14 @@ ${diagnostic}` : "";
|
|
|
5520
5525
|
}
|
|
5521
5526
|
async function preflightCloudflareWrangler(opts = {}) {
|
|
5522
5527
|
const runner = opts.run ?? runWranglerCapture;
|
|
5528
|
+
const deliveryMode = opts.deliveryMode ?? "direct-push";
|
|
5523
5529
|
const help = await runner(
|
|
5524
5530
|
"wrangler",
|
|
5525
5531
|
["deploy", "--help"],
|
|
5526
5532
|
{ cwd: path2.resolve(opts.cwd ?? process.cwd()) }
|
|
5527
5533
|
);
|
|
5528
|
-
const
|
|
5534
|
+
const requiredFlags = deliveryMode === "direct-push" ? ["--dry-run", "--secrets-file", "--strict"] : ["--dry-run", "--strict"];
|
|
5535
|
+
const missing = requiredFlags.filter((flag) => !help.includes(flag));
|
|
5529
5536
|
if (missing.length > 0) {
|
|
5530
5537
|
throw new Error(`Wrangler deploy does not support required flags: ${missing.join(", ")}`);
|
|
5531
5538
|
}
|
|
@@ -5539,29 +5546,38 @@ async function preflightCloudflareWrangler(opts = {}) {
|
|
|
5539
5546
|
try {
|
|
5540
5547
|
fs4.chmodSync(tempDirectory, 448);
|
|
5541
5548
|
fs4.writeFileSync(workerScriptPath, generateWorkerScript({
|
|
5542
|
-
deliveryMode
|
|
5549
|
+
deliveryMode,
|
|
5543
5550
|
workerVersion: "preflight",
|
|
5544
5551
|
botList: DEFAULT_BOT_LIST
|
|
5545
5552
|
}), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
5546
|
-
fs4.writeFileSync(wranglerTomlPath, generateWranglerToml(
|
|
5547
|
-
deliveryMode
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5553
|
+
fs4.writeFileSync(wranglerTomlPath, generateWranglerToml(
|
|
5554
|
+
deliveryMode === "queue-pull" ? {
|
|
5555
|
+
deliveryMode,
|
|
5556
|
+
sourceId: "preflight",
|
|
5557
|
+
hostname: "example.invalid",
|
|
5558
|
+
queueName: "canonry-preflight",
|
|
5559
|
+
workerVersion: "preflight"
|
|
5560
|
+
} : {
|
|
5561
|
+
deliveryMode,
|
|
5562
|
+
sourceId: "preflight",
|
|
5563
|
+
hostname: "example.invalid",
|
|
5564
|
+
ingestUrl: "https://canonry.example.invalid/api/v1/projects/preflight/traffic/cloudflare/ingest",
|
|
5565
|
+
workerVersion: "preflight"
|
|
5566
|
+
}
|
|
5567
|
+
), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
5568
|
+
if (deliveryMode === "direct-push") {
|
|
5569
|
+
fs4.writeFileSync(secretsPath, JSON.stringify({
|
|
5570
|
+
[CLOUDFLARE_WORKER_BINDINGS.bearerToken]: "preflight-bearer",
|
|
5571
|
+
[CLOUDFLARE_WORKER_BINDINGS.hmacSecret]: "preflight-hmac"
|
|
5572
|
+
}), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
5573
|
+
}
|
|
5557
5574
|
const validationOutput = await runner(
|
|
5558
5575
|
"wrangler",
|
|
5559
5576
|
[
|
|
5560
5577
|
"deploy",
|
|
5561
5578
|
"--config",
|
|
5562
5579
|
wranglerTomlPath,
|
|
5563
|
-
"--secrets-file",
|
|
5564
|
-
secretsPath,
|
|
5580
|
+
...deliveryMode === "direct-push" ? ["--secrets-file", secretsPath] : [],
|
|
5565
5581
|
"--strict",
|
|
5566
5582
|
"--dry-run",
|
|
5567
5583
|
"--outdir",
|
|
@@ -5582,6 +5598,18 @@ ${wranglerDiagnostic(validationOutput)}`
|
|
|
5582
5598
|
}
|
|
5583
5599
|
}
|
|
5584
5600
|
async function deployCloudflareWorker(opts) {
|
|
5601
|
+
const deliveryMode = opts.deliveryMode ?? "direct-push";
|
|
5602
|
+
if (deliveryMode === "queue-pull") {
|
|
5603
|
+
const runner = opts.run ?? runWrangler;
|
|
5604
|
+
await runner(
|
|
5605
|
+
"wrangler",
|
|
5606
|
+
["deploy", "--config", path2.resolve(opts.wranglerTomlPath), "--strict"],
|
|
5607
|
+
{ cwd: path2.dirname(path2.resolve(opts.wranglerTomlPath)) }
|
|
5608
|
+
);
|
|
5609
|
+
return;
|
|
5610
|
+
}
|
|
5611
|
+
if (!opts.secrets) throw new Error("Direct-push Worker deploy requires bearer and HMAC secrets");
|
|
5612
|
+
const secrets = opts.secrets;
|
|
5585
5613
|
const tempDirectory = fs4.mkdtempSync(path2.join(opts.tempRoot ?? os.tmpdir(), "canonry-cloudflare-secrets-"));
|
|
5586
5614
|
const secretsPath = path2.join(tempDirectory, "secrets.json");
|
|
5587
5615
|
try {
|
|
@@ -5589,8 +5617,8 @@ async function deployCloudflareWorker(opts) {
|
|
|
5589
5617
|
fs4.writeFileSync(
|
|
5590
5618
|
secretsPath,
|
|
5591
5619
|
JSON.stringify({
|
|
5592
|
-
[CLOUDFLARE_WORKER_BINDINGS.bearerToken]:
|
|
5593
|
-
[CLOUDFLARE_WORKER_BINDINGS.hmacSecret]:
|
|
5620
|
+
[CLOUDFLARE_WORKER_BINDINGS.bearerToken]: secrets.bearerToken,
|
|
5621
|
+
[CLOUDFLARE_WORKER_BINDINGS.hmacSecret]: secrets.hmacSecret
|
|
5594
5622
|
}),
|
|
5595
5623
|
{ encoding: "utf-8", flag: "wx", mode: 384 }
|
|
5596
5624
|
);
|
|
@@ -5618,6 +5646,9 @@ async function deployCloudflareWorker(opts) {
|
|
|
5618
5646
|
}
|
|
5619
5647
|
|
|
5620
5648
|
// src/commands/traffic.ts
|
|
5649
|
+
var DEFAULT_CLOUDFLARE_QUEUE_RETENTION_SECONDS = 345600;
|
|
5650
|
+
var CLOUDFLARE_QUEUE_RETENTION_MIN_SECONDS = 60;
|
|
5651
|
+
var CLOUDFLARE_QUEUE_RETENTION_MAX_SECONDS = 1209600;
|
|
5621
5652
|
function getClient9() {
|
|
5622
5653
|
return createApiClient();
|
|
5623
5654
|
}
|
|
@@ -5627,7 +5658,60 @@ function configString(value, fallback = "(unset)") {
|
|
|
5627
5658
|
function errorMessage2(error) {
|
|
5628
5659
|
return error instanceof Error ? error.message : String(error);
|
|
5629
5660
|
}
|
|
5661
|
+
function requireCloudflareQueueOption(project, value, option) {
|
|
5662
|
+
if (value?.trim()) return value.trim();
|
|
5663
|
+
const code = option === "--account-id" ? "TRAFFIC_CLOUDFLARE_QUEUE_ACCOUNT_REQUIRED" : option === "--queue-id" ? "TRAFFIC_CLOUDFLARE_QUEUE_ID_REQUIRED" : option === "--queue-name" ? "TRAFFIC_CLOUDFLARE_QUEUE_NAME_REQUIRED" : "TRAFFIC_CLOUDFLARE_QUEUE_TOKEN_FILE_REQUIRED";
|
|
5664
|
+
throw new CliError({
|
|
5665
|
+
code,
|
|
5666
|
+
message: `${option} is required with --delivery-mode queue-pull`,
|
|
5667
|
+
displayMessage: `Error: ${option} is required with --delivery-mode queue-pull`,
|
|
5668
|
+
details: { project }
|
|
5669
|
+
});
|
|
5670
|
+
}
|
|
5671
|
+
function readCloudflareQueueApiToken(project, tokenFile) {
|
|
5672
|
+
try {
|
|
5673
|
+
const stat = fs5.lstatSync(tokenFile);
|
|
5674
|
+
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
5675
|
+
throw new Error("not a regular file");
|
|
5676
|
+
}
|
|
5677
|
+
const apiToken = fs5.readFileSync(tokenFile, "utf-8").trim();
|
|
5678
|
+
if (!apiToken) throw new Error("file is empty");
|
|
5679
|
+
return apiToken;
|
|
5680
|
+
} catch (error) {
|
|
5681
|
+
const message = errorMessage2(error);
|
|
5682
|
+
throw new CliError({
|
|
5683
|
+
code: "TRAFFIC_CLOUDFLARE_QUEUE_TOKEN_FILE_READ_ERROR",
|
|
5684
|
+
message: `Failed to read --api-token-file: ${message}`,
|
|
5685
|
+
displayMessage: `Error: failed to read --api-token-file "${tokenFile}": ${message}`,
|
|
5686
|
+
details: { project, tokenFile }
|
|
5687
|
+
});
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5630
5690
|
async function trafficConnectCloudflare(project, opts, deps = {}) {
|
|
5691
|
+
const deliveryMode = opts.deliveryMode ?? "direct-push";
|
|
5692
|
+
let queuePull;
|
|
5693
|
+
if (deliveryMode === "queue-pull") {
|
|
5694
|
+
const accountId = requireCloudflareQueueOption(project, opts.accountId, "--account-id");
|
|
5695
|
+
const queueId = requireCloudflareQueueOption(project, opts.queueId, "--queue-id");
|
|
5696
|
+
const queueName = requireCloudflareQueueOption(project, opts.queueName, "--queue-name");
|
|
5697
|
+
const tokenFile = requireCloudflareQueueOption(project, opts.apiTokenFile, "--api-token-file");
|
|
5698
|
+
const retentionSeconds = opts.retentionSeconds ?? DEFAULT_CLOUDFLARE_QUEUE_RETENTION_SECONDS;
|
|
5699
|
+
if (!Number.isInteger(retentionSeconds) || retentionSeconds < CLOUDFLARE_QUEUE_RETENTION_MIN_SECONDS || retentionSeconds > CLOUDFLARE_QUEUE_RETENTION_MAX_SECONDS) {
|
|
5700
|
+
throw new CliError({
|
|
5701
|
+
code: "TRAFFIC_CLOUDFLARE_QUEUE_RETENTION_INVALID",
|
|
5702
|
+
message: "--retention-seconds must be an integer between 60 and 1209600",
|
|
5703
|
+
displayMessage: "Error: --retention-seconds must be an integer between 60 and 1209600",
|
|
5704
|
+
details: { project }
|
|
5705
|
+
});
|
|
5706
|
+
}
|
|
5707
|
+
queuePull = {
|
|
5708
|
+
accountId,
|
|
5709
|
+
queueId,
|
|
5710
|
+
queueName,
|
|
5711
|
+
apiToken: readCloudflareQueueApiToken(project, tokenFile),
|
|
5712
|
+
retentionSeconds
|
|
5713
|
+
};
|
|
5714
|
+
}
|
|
5631
5715
|
if (opts.deploy && !opts.zoneId) {
|
|
5632
5716
|
throw new CliError({
|
|
5633
5717
|
code: "TRAFFIC_CLOUDFLARE_DEPLOY_ZONE_REQUIRED",
|
|
@@ -5654,7 +5738,7 @@ async function trafficConnectCloudflare(project, opts, deps = {}) {
|
|
|
5654
5738
|
}
|
|
5655
5739
|
if (opts.deploy) {
|
|
5656
5740
|
try {
|
|
5657
|
-
await (deps.preflightWrangler ?? preflightCloudflareWrangler)();
|
|
5741
|
+
await (deps.preflightWrangler ?? preflightCloudflareWrangler)({ deliveryMode });
|
|
5658
5742
|
} catch (error) {
|
|
5659
5743
|
const message = errorMessage2(error);
|
|
5660
5744
|
throw new CliError({
|
|
@@ -5680,18 +5764,27 @@ ${message}`,
|
|
|
5680
5764
|
});
|
|
5681
5765
|
}
|
|
5682
5766
|
const client = deps.client ?? getClient9();
|
|
5683
|
-
const result = await client.trafficConnectCloudflare(
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5767
|
+
const result = await client.trafficConnectCloudflare(
|
|
5768
|
+
project,
|
|
5769
|
+
deliveryMode === "queue-pull" ? {
|
|
5770
|
+
deliveryMode,
|
|
5771
|
+
displayName: opts.displayName,
|
|
5772
|
+
zoneId: opts.zoneId,
|
|
5773
|
+
...queuePull
|
|
5774
|
+
} : {
|
|
5775
|
+
deliveryMode,
|
|
5776
|
+
displayName: opts.displayName,
|
|
5777
|
+
zoneId: opts.zoneId,
|
|
5778
|
+
accountId: opts.accountId
|
|
5779
|
+
}
|
|
5780
|
+
);
|
|
5689
5781
|
const localConfig = (deps.loadLocalConfig ?? loadConfigRaw)();
|
|
5690
|
-
const localCredential = localConfig ?
|
|
5691
|
-
const deploymentCredential = localCredential?.
|
|
5692
|
-
|
|
5782
|
+
const localCredential = localConfig ? getCloudflareTrafficConnectionBySourceId(localConfig, result.sourceId) : void 0;
|
|
5783
|
+
const deploymentCredential = localCredential?.deliveryMode === result.deliveryMode ? localCredential : void 0;
|
|
5784
|
+
const artifactSecrets = deploymentCredential ?? (queuePull ? { apiToken: queuePull.apiToken } : void 0);
|
|
5785
|
+
if (artifactSecrets) {
|
|
5693
5786
|
try {
|
|
5694
|
-
assertCloudflareArtifactsDoNotContainSecrets(result,
|
|
5787
|
+
assertCloudflareArtifactsDoNotContainSecrets(result, artifactSecrets);
|
|
5695
5788
|
} catch {
|
|
5696
5789
|
throw new CliError({
|
|
5697
5790
|
code: "TRAFFIC_CLOUDFLARE_SECRET_EXPOSURE",
|
|
@@ -5712,7 +5805,7 @@ ${message}`,
|
|
|
5712
5805
|
details: { project, sourceId: result.sourceId, outputDirectory }
|
|
5713
5806
|
});
|
|
5714
5807
|
}
|
|
5715
|
-
if (opts.deploy && !deploymentCredential) {
|
|
5808
|
+
if (opts.deploy && result.deliveryMode === "direct-push" && !deploymentCredential) {
|
|
5716
5809
|
throw new CliError({
|
|
5717
5810
|
code: "TRAFFIC_CLOUDFLARE_DEPLOY_CONFIG_UNSHARED",
|
|
5718
5811
|
message: "Cloudflare auto-deploy requires the CLI and Canonry server to share the same local config",
|
|
@@ -5724,7 +5817,7 @@ ${message}`,
|
|
|
5724
5817
|
}
|
|
5725
5818
|
});
|
|
5726
5819
|
}
|
|
5727
|
-
if (opts.deploy && deploymentCredential) {
|
|
5820
|
+
if (opts.deploy && result.deliveryMode === "direct-push" && deploymentCredential?.deliveryMode === "direct-push") {
|
|
5728
5821
|
try {
|
|
5729
5822
|
await (deps.deployWorker ?? deployCloudflareWorker)({
|
|
5730
5823
|
wranglerTomlPath: artifacts.wranglerTomlPath,
|
|
@@ -5740,16 +5833,40 @@ ${message}`,
|
|
|
5740
5833
|
});
|
|
5741
5834
|
}
|
|
5742
5835
|
}
|
|
5836
|
+
if (opts.deploy && result.deliveryMode === "queue-pull") {
|
|
5837
|
+
try {
|
|
5838
|
+
await (deps.deployWorker ?? deployCloudflareWorker)({
|
|
5839
|
+
wranglerTomlPath: artifacts.wranglerTomlPath,
|
|
5840
|
+
deliveryMode: "queue-pull"
|
|
5841
|
+
});
|
|
5842
|
+
} catch (error) {
|
|
5843
|
+
const message = artifactSecrets ? redactCloudflareSecrets(errorMessage2(error), artifactSecrets) : errorMessage2(error);
|
|
5844
|
+
throw new CliError({
|
|
5845
|
+
code: "TRAFFIC_CLOUDFLARE_DEPLOY_FAILED",
|
|
5846
|
+
message,
|
|
5847
|
+
displayMessage: `Error: Cloudflare source connected and artifacts written, but Wrangler deploy failed: ${message}`,
|
|
5848
|
+
details: { project, sourceId: result.sourceId, outputDirectory }
|
|
5849
|
+
});
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5743
5852
|
const summary = {
|
|
5744
5853
|
sourceId: result.sourceId,
|
|
5745
5854
|
deliveryMode: result.deliveryMode,
|
|
5855
|
+
activationRequired: result.activationRequired === true,
|
|
5746
5856
|
workerVersion: result.workerVersion,
|
|
5747
5857
|
outputDirectory: artifacts.outputDirectory,
|
|
5748
5858
|
files: {
|
|
5749
5859
|
workerScript: artifacts.workerScriptPath,
|
|
5750
5860
|
wranglerConfig: artifacts.wranglerTomlPath
|
|
5751
5861
|
},
|
|
5752
|
-
autoDeployAvailable: Boolean(deploymentCredential),
|
|
5862
|
+
autoDeployAvailable: result.deliveryMode === "queue-pull" || Boolean(deploymentCredential),
|
|
5863
|
+
...result.deliveryMode === "queue-pull" ? {
|
|
5864
|
+
queuePullConsumer: {
|
|
5865
|
+
required: true,
|
|
5866
|
+
queueName: result.queueName,
|
|
5867
|
+
configuredBy: "wrangler-or-cloudflare-dashboard"
|
|
5868
|
+
}
|
|
5869
|
+
} : {},
|
|
5753
5870
|
deployment: opts.deploy ? "worker-deployed-route-unattached" : "not-requested",
|
|
5754
5871
|
routeAttachment: "required-manual",
|
|
5755
5872
|
requestLimitFailureMode: {
|
|
@@ -5764,7 +5881,7 @@ ${message}`,
|
|
|
5764
5881
|
console.log(JSON.stringify(summary, null, 2));
|
|
5765
5882
|
return;
|
|
5766
5883
|
}
|
|
5767
|
-
console.log(`Cloudflare
|
|
5884
|
+
console.log(`Cloudflare ${result.deliveryMode} traffic source connected for project "${project}".`);
|
|
5768
5885
|
console.log(` Source ID: ${result.sourceId}`);
|
|
5769
5886
|
console.log(` Worker version: ${result.workerVersion}`);
|
|
5770
5887
|
console.log(` Worker script: ${artifacts.workerScriptPath}`);
|
|
@@ -5776,17 +5893,42 @@ ${message}`,
|
|
|
5776
5893
|
console.log("Required: set the route Request limit failure mode to Fail open before route activation.");
|
|
5777
5894
|
console.log("Wrangler cannot configure this toggle. Workers Free includes 100,000 requests per day for the account.");
|
|
5778
5895
|
console.log("Use one authoritative server-traffic source for this site. Overlapping adapters double-count project totals.");
|
|
5896
|
+
if (result.deliveryMode === "queue-pull") {
|
|
5897
|
+
console.log(`Required: enable HTTP pull with \`wrangler queues consumer http add ${result.queueName}\` before the first sync.`);
|
|
5898
|
+
}
|
|
5899
|
+
if (result.activationRequired) {
|
|
5900
|
+
console.log(`Activation required: run \`canonry traffic activate ${project} --source ${result.sourceId}\`. This command does not activate delivery.`);
|
|
5901
|
+
}
|
|
5779
5902
|
if (opts.deploy) {
|
|
5780
5903
|
console.log("");
|
|
5781
5904
|
console.log("Required Cloudflare Dashboard steps:");
|
|
5782
5905
|
console.log(result.instructions);
|
|
5783
|
-
|
|
5906
|
+
if (result.deliveryMode === "direct-push") {
|
|
5907
|
+
console.log("Keep the Canonry public HTTPS URL reachable so the Worker can push events.");
|
|
5908
|
+
}
|
|
5784
5909
|
} else if (deploymentCredential) {
|
|
5785
5910
|
console.log("Next: install and authenticate Wrangler. Inspect the route, then rerun with --deploy --confirm-route --confirm-fail-open and --zone-id <id>.");
|
|
5911
|
+
} else if (result.deliveryMode === "queue-pull") {
|
|
5912
|
+
console.log("Next: install and authenticate Wrangler externally, then rerun with --deploy --confirm-route --confirm-fail-open and --zone-id <id>.");
|
|
5786
5913
|
} else {
|
|
5787
5914
|
console.log("Auto-deploy is unavailable because this CLI and the Canonry server do not share local config. Ask the server operator to deploy and install the Worker secrets.");
|
|
5788
5915
|
}
|
|
5789
5916
|
}
|
|
5917
|
+
async function trafficActivate(project, opts, deps = {}) {
|
|
5918
|
+
const client = deps.client ?? getClient9();
|
|
5919
|
+
const source = await client.trafficActivate(project, opts.sourceId);
|
|
5920
|
+
if (isMachineFormat(opts.format)) {
|
|
5921
|
+
console.log(JSON.stringify(source, null, 2));
|
|
5922
|
+
return;
|
|
5923
|
+
}
|
|
5924
|
+
const sourceMode = typeof source.config.deliveryMode === "string" ? source.config.deliveryMode : source.sourceType;
|
|
5925
|
+
const trafficSync2 = sourceMode === "direct-push" ? "not required for direct-push delivery" : "enabled for this pull source";
|
|
5926
|
+
console.log(`Traffic source activated for project "${project}".`);
|
|
5927
|
+
console.log(` Source ID: ${source.id}`);
|
|
5928
|
+
console.log(` Source mode: ${sourceMode}`);
|
|
5929
|
+
console.log(` Status: ${source.status}`);
|
|
5930
|
+
console.log(` Traffic sync: ${trafficSync2}`);
|
|
5931
|
+
}
|
|
5790
5932
|
async function trafficConnectWordpress(project, opts) {
|
|
5791
5933
|
if (!opts.url) {
|
|
5792
5934
|
throw new CliError({
|
|
@@ -5814,9 +5956,9 @@ async function trafficConnectWordpress(project, opts) {
|
|
|
5814
5956
|
}
|
|
5815
5957
|
let applicationPassword = opts.appPassword?.trim() ?? "";
|
|
5816
5958
|
if (!applicationPassword && opts.appPasswordFile) {
|
|
5817
|
-
const
|
|
5959
|
+
const fs19 = await import("fs");
|
|
5818
5960
|
try {
|
|
5819
|
-
applicationPassword =
|
|
5961
|
+
applicationPassword = fs19.readFileSync(opts.appPasswordFile, "utf-8").trim();
|
|
5820
5962
|
} catch (e) {
|
|
5821
5963
|
const msg = e instanceof Error ? e.message : String(e);
|
|
5822
5964
|
throw new CliError({
|
|
@@ -5872,10 +6014,10 @@ async function trafficConnectCloudRun(project, opts) {
|
|
|
5872
6014
|
details: { project }
|
|
5873
6015
|
});
|
|
5874
6016
|
}
|
|
5875
|
-
const
|
|
6017
|
+
const fs19 = await import("fs");
|
|
5876
6018
|
let keyJson;
|
|
5877
6019
|
try {
|
|
5878
|
-
keyJson =
|
|
6020
|
+
keyJson = fs19.readFileSync(opts.serviceAccountKey, "utf-8");
|
|
5879
6021
|
JSON.parse(keyJson);
|
|
5880
6022
|
} catch (e) {
|
|
5881
6023
|
const msg = e instanceof Error ? e.message : String(e);
|
|
@@ -5935,9 +6077,9 @@ async function trafficConnectVercel(project, opts) {
|
|
|
5935
6077
|
}
|
|
5936
6078
|
let token = opts.token?.trim() ?? "";
|
|
5937
6079
|
if (!token && opts.tokenFile) {
|
|
5938
|
-
const
|
|
6080
|
+
const fs19 = await import("fs");
|
|
5939
6081
|
try {
|
|
5940
|
-
token =
|
|
6082
|
+
token = fs19.readFileSync(opts.tokenFile, "utf-8").trim();
|
|
5941
6083
|
} catch (e) {
|
|
5942
6084
|
const msg = e instanceof Error ? e.message : String(e);
|
|
5943
6085
|
throw new CliError({
|
|
@@ -6288,11 +6430,16 @@ async function trafficEvents(project, opts) {
|
|
|
6288
6430
|
var TRAFFIC_CLI_COMMANDS = [
|
|
6289
6431
|
{
|
|
6290
6432
|
path: ["traffic", "connect", "cloudflare"],
|
|
6291
|
-
usage: "canonry traffic connect cloudflare <project> [--display-name <name>] [--zone-id <id>] [--account-id <id>] [--output-dir <dir>] [--deploy --confirm-route --confirm-fail-open] [--format json]",
|
|
6433
|
+
usage: "canonry traffic connect cloudflare <project> [--delivery-mode direct-push|queue-pull] [--display-name <name>] [--zone-id <id>] [--account-id <id>] [--queue-id <id> --queue-name <name> --api-token-file <path> --retention-seconds 345600] [--output-dir <dir>] [--deploy --confirm-route --confirm-fail-open] [--format json]",
|
|
6292
6434
|
options: {
|
|
6293
6435
|
"display-name": stringOption(),
|
|
6294
6436
|
"zone-id": stringOption(),
|
|
6295
6437
|
"account-id": stringOption(),
|
|
6438
|
+
"delivery-mode": stringOption(),
|
|
6439
|
+
"queue-id": stringOption(),
|
|
6440
|
+
"queue-name": stringOption(),
|
|
6441
|
+
"api-token-file": stringOption(),
|
|
6442
|
+
"retention-seconds": stringOption(),
|
|
6296
6443
|
"output-dir": stringOption(),
|
|
6297
6444
|
deploy: { type: "boolean" },
|
|
6298
6445
|
"confirm-route": { type: "boolean" },
|
|
@@ -6302,12 +6449,26 @@ var TRAFFIC_CLI_COMMANDS = [
|
|
|
6302
6449
|
const project = requireProject(
|
|
6303
6450
|
input,
|
|
6304
6451
|
"traffic.connect.cloudflare",
|
|
6305
|
-
"canonry traffic connect cloudflare <project> [--zone-id <id>] [--output-dir <dir>] [--deploy --confirm-route --confirm-fail-open]"
|
|
6452
|
+
"canonry traffic connect cloudflare <project> [--delivery-mode direct-push|queue-pull] [--zone-id <id>] [--output-dir <dir>] [--deploy --confirm-route --confirm-fail-open]"
|
|
6306
6453
|
);
|
|
6454
|
+
const deliveryMode = getString(input.values, "delivery-mode") ?? "direct-push";
|
|
6455
|
+
if (deliveryMode !== "direct-push" && deliveryMode !== "queue-pull") {
|
|
6456
|
+
throw new Error("--delivery-mode must be direct-push or queue-pull");
|
|
6457
|
+
}
|
|
6458
|
+
const retentionSeconds = parseIntegerOption(input, "retention-seconds", {
|
|
6459
|
+
command: "traffic.connect.cloudflare",
|
|
6460
|
+
usage: "canonry traffic connect cloudflare <project> --delivery-mode queue-pull --retention-seconds 345600",
|
|
6461
|
+
message: "--retention-seconds must be an integer"
|
|
6462
|
+
});
|
|
6307
6463
|
await trafficConnectCloudflare(project, {
|
|
6464
|
+
deliveryMode,
|
|
6308
6465
|
displayName: getString(input.values, "display-name"),
|
|
6309
6466
|
zoneId: getString(input.values, "zone-id"),
|
|
6310
6467
|
accountId: getString(input.values, "account-id"),
|
|
6468
|
+
queueId: getString(input.values, "queue-id"),
|
|
6469
|
+
queueName: getString(input.values, "queue-name"),
|
|
6470
|
+
apiTokenFile: getString(input.values, "api-token-file"),
|
|
6471
|
+
retentionSeconds: retentionSeconds ?? DEFAULT_CLOUDFLARE_QUEUE_RETENTION_SECONDS,
|
|
6311
6472
|
outputDirectory: getString(input.values, "output-dir"),
|
|
6312
6473
|
deploy: getBoolean(input.values, "deploy"),
|
|
6313
6474
|
confirmRoute: getBoolean(input.values, "confirm-route"),
|
|
@@ -6419,6 +6580,23 @@ var TRAFFIC_CLI_COMMANDS = [
|
|
|
6419
6580
|
});
|
|
6420
6581
|
}
|
|
6421
6582
|
},
|
|
6583
|
+
{
|
|
6584
|
+
path: ["traffic", "activate"],
|
|
6585
|
+
usage: "canonry traffic activate <project> --source <id> [--format json]",
|
|
6586
|
+
options: {
|
|
6587
|
+
source: stringOption()
|
|
6588
|
+
},
|
|
6589
|
+
run: async (input) => {
|
|
6590
|
+
const project = requireProject(
|
|
6591
|
+
input,
|
|
6592
|
+
"traffic.activate",
|
|
6593
|
+
"canonry traffic activate <project> --source <id>"
|
|
6594
|
+
);
|
|
6595
|
+
const sourceId = getString(input.values, "source");
|
|
6596
|
+
if (!sourceId) throw new Error("--source <id> is required");
|
|
6597
|
+
await trafficActivate(project, { sourceId, format: input.format });
|
|
6598
|
+
}
|
|
6599
|
+
},
|
|
6422
6600
|
{
|
|
6423
6601
|
path: ["traffic", "sync"],
|
|
6424
6602
|
usage: "canonry traffic sync <project> --source <id> [--since-minutes 43200] [--format json]",
|
|
@@ -6568,7 +6746,7 @@ var TRAFFIC_CLI_COMMANDS = [
|
|
|
6568
6746
|
unknownSubcommand(input.positionals[0], {
|
|
6569
6747
|
command: "traffic",
|
|
6570
6748
|
usage: "canonry traffic <subcommand> <project> [args]",
|
|
6571
|
-
available: ["connect", "sync", "backfill", "status", "sources", "events"]
|
|
6749
|
+
available: ["connect", "activate", "sync", "backfill", "status", "sources", "events"]
|
|
6572
6750
|
});
|
|
6573
6751
|
}
|
|
6574
6752
|
}
|
|
@@ -8310,7 +8488,7 @@ var USERS_CLI_COMMANDS = [
|
|
|
8310
8488
|
];
|
|
8311
8489
|
|
|
8312
8490
|
// src/commands/keyword.ts
|
|
8313
|
-
import
|
|
8491
|
+
import fs6 from "fs";
|
|
8314
8492
|
function getClient14() {
|
|
8315
8493
|
return createApiClient();
|
|
8316
8494
|
}
|
|
@@ -8378,7 +8556,7 @@ async function listKeywords(project, format) {
|
|
|
8378
8556
|
}
|
|
8379
8557
|
}
|
|
8380
8558
|
async function importKeywords(project, filePath, format) {
|
|
8381
|
-
if (!
|
|
8559
|
+
if (!fs6.existsSync(filePath)) {
|
|
8382
8560
|
throw new CliError({
|
|
8383
8561
|
code: "KEYWORD_IMPORT_FILE_NOT_FOUND",
|
|
8384
8562
|
message: `File not found: ${filePath}`,
|
|
@@ -8389,7 +8567,7 @@ async function importKeywords(project, filePath, format) {
|
|
|
8389
8567
|
}
|
|
8390
8568
|
});
|
|
8391
8569
|
}
|
|
8392
|
-
const content =
|
|
8570
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
8393
8571
|
const keywords = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
8394
8572
|
if (keywords.length === 0) {
|
|
8395
8573
|
if (isMachineFormat(format)) {
|
|
@@ -8590,7 +8768,7 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
8590
8768
|
];
|
|
8591
8769
|
|
|
8592
8770
|
// src/commands/query.ts
|
|
8593
|
-
import
|
|
8771
|
+
import fs7 from "fs";
|
|
8594
8772
|
function getClient15() {
|
|
8595
8773
|
return createApiClient();
|
|
8596
8774
|
}
|
|
@@ -8681,7 +8859,7 @@ async function listQueries(project, format) {
|
|
|
8681
8859
|
}
|
|
8682
8860
|
}
|
|
8683
8861
|
async function importQueries(project, filePath, format) {
|
|
8684
|
-
if (!
|
|
8862
|
+
if (!fs7.existsSync(filePath)) {
|
|
8685
8863
|
throw new CliError({
|
|
8686
8864
|
code: "QUERY_IMPORT_FILE_NOT_FOUND",
|
|
8687
8865
|
message: `File not found: ${filePath}`,
|
|
@@ -8692,7 +8870,7 @@ async function importQueries(project, filePath, format) {
|
|
|
8692
8870
|
}
|
|
8693
8871
|
});
|
|
8694
8872
|
}
|
|
8695
|
-
const content =
|
|
8873
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
8696
8874
|
const queries2 = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
8697
8875
|
if (queries2.length === 0) {
|
|
8698
8876
|
if (isMachineFormat(format)) {
|
|
@@ -8894,7 +9072,7 @@ var QUERY_CLI_COMMANDS = [
|
|
|
8894
9072
|
];
|
|
8895
9073
|
|
|
8896
9074
|
// src/commands/mcp.ts
|
|
8897
|
-
import
|
|
9075
|
+
import fs8 from "fs";
|
|
8898
9076
|
import path4 from "path";
|
|
8899
9077
|
import { createRequire } from "module";
|
|
8900
9078
|
|
|
@@ -9010,8 +9188,8 @@ function renderClientSnippet(client, serverName, entry) {
|
|
|
9010
9188
|
return renderJsonSnippet(serverName, entry, client.format);
|
|
9011
9189
|
}
|
|
9012
9190
|
function readJsonConfig(configPath) {
|
|
9013
|
-
if (!
|
|
9014
|
-
const raw =
|
|
9191
|
+
if (!fs8.existsSync(configPath)) return {};
|
|
9192
|
+
const raw = fs8.readFileSync(configPath, "utf-8").trim();
|
|
9015
9193
|
if (!raw) return {};
|
|
9016
9194
|
try {
|
|
9017
9195
|
const parsed = JSON.parse(raw);
|
|
@@ -9029,14 +9207,14 @@ function readJsonConfig(configPath) {
|
|
|
9029
9207
|
}
|
|
9030
9208
|
}
|
|
9031
9209
|
function writeJsonConfig(configPath, value) {
|
|
9032
|
-
|
|
9033
|
-
|
|
9210
|
+
fs8.mkdirSync(path4.dirname(configPath), { recursive: true });
|
|
9211
|
+
fs8.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
|
|
9034
9212
|
`, "utf-8");
|
|
9035
9213
|
}
|
|
9036
9214
|
function backupConfigIfPresent(configPath) {
|
|
9037
|
-
if (!
|
|
9215
|
+
if (!fs8.existsSync(configPath)) return void 0;
|
|
9038
9216
|
const backupPath = `${configPath}.canonry.bak`;
|
|
9039
|
-
|
|
9217
|
+
fs8.copyFileSync(configPath, backupPath);
|
|
9040
9218
|
return backupPath;
|
|
9041
9219
|
}
|
|
9042
9220
|
function findClientOrThrow(id) {
|
|
@@ -9392,13 +9570,13 @@ var NOTIFY_CLI_COMMANDS = [
|
|
|
9392
9570
|
];
|
|
9393
9571
|
|
|
9394
9572
|
// src/commands/apply.ts
|
|
9395
|
-
import
|
|
9573
|
+
import fs9 from "fs";
|
|
9396
9574
|
import { parseAllDocuments } from "yaml";
|
|
9397
9575
|
async function applyConfigFile(filePath) {
|
|
9398
|
-
if (!
|
|
9576
|
+
if (!fs9.existsSync(filePath)) {
|
|
9399
9577
|
throw new Error(`File not found: ${filePath}`);
|
|
9400
9578
|
}
|
|
9401
|
-
const content =
|
|
9579
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
9402
9580
|
const docs = parseAllDocuments(content);
|
|
9403
9581
|
const client = createApiClient();
|
|
9404
9582
|
const errors = [];
|
|
@@ -9801,7 +9979,7 @@ async function loadLatestRunForExport(client, project) {
|
|
|
9801
9979
|
}
|
|
9802
9980
|
|
|
9803
9981
|
// src/commands/results-export.ts
|
|
9804
|
-
import
|
|
9982
|
+
import fs10 from "fs";
|
|
9805
9983
|
import path5 from "path";
|
|
9806
9984
|
async function exportResults(project, opts) {
|
|
9807
9985
|
const { output, ...request } = opts;
|
|
@@ -9811,8 +9989,8 @@ async function exportResults(project, opts) {
|
|
|
9811
9989
|
return;
|
|
9812
9990
|
}
|
|
9813
9991
|
const target = output ? path5.resolve(output) : path5.resolve(process.cwd(), path5.basename(artifact.filename));
|
|
9814
|
-
|
|
9815
|
-
|
|
9992
|
+
fs10.mkdirSync(path5.dirname(target), { recursive: true });
|
|
9993
|
+
fs10.writeFileSync(target, artifact.content, "utf8");
|
|
9816
9994
|
console.log(`Results export written to ${target}`);
|
|
9817
9995
|
}
|
|
9818
9996
|
|
|
@@ -10528,7 +10706,7 @@ function parseProviderModelAssignments(assignments) {
|
|
|
10528
10706
|
}
|
|
10529
10707
|
|
|
10530
10708
|
// src/commands/report.ts
|
|
10531
|
-
import
|
|
10709
|
+
import fs11 from "fs";
|
|
10532
10710
|
import path6 from "path";
|
|
10533
10711
|
function defaultOutputPath(project, audience) {
|
|
10534
10712
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -10545,10 +10723,10 @@ async function runReportCommand(project, opts = {}) {
|
|
|
10545
10723
|
const html = renderReportHtml(report, { audience });
|
|
10546
10724
|
const targetPath = opts.output ? path6.resolve(opts.output) : defaultOutputPath(project, audience);
|
|
10547
10725
|
const dir = path6.dirname(targetPath);
|
|
10548
|
-
if (!
|
|
10549
|
-
|
|
10726
|
+
if (!fs11.existsSync(dir)) {
|
|
10727
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
10550
10728
|
}
|
|
10551
|
-
|
|
10729
|
+
fs11.writeFileSync(targetPath, html, "utf-8");
|
|
10552
10730
|
console.log(`Report written to ${targetPath}`);
|
|
10553
10731
|
}
|
|
10554
10732
|
|
|
@@ -11523,11 +11701,11 @@ var SKILLS_CLI_COMMANDS = [
|
|
|
11523
11701
|
];
|
|
11524
11702
|
|
|
11525
11703
|
// src/commands/snapshot.ts
|
|
11526
|
-
import
|
|
11704
|
+
import fs13 from "fs";
|
|
11527
11705
|
import path8 from "path";
|
|
11528
11706
|
|
|
11529
11707
|
// src/snapshot-pdf.ts
|
|
11530
|
-
import
|
|
11708
|
+
import fs12 from "fs";
|
|
11531
11709
|
import path7 from "path";
|
|
11532
11710
|
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
11533
11711
|
var PAGE_WIDTH = 612;
|
|
@@ -11741,8 +11919,8 @@ async function writeSnapshotPdf(report, outputPath) {
|
|
|
11741
11919
|
renderQueries(pdf, report);
|
|
11742
11920
|
const bytes = await doc.save();
|
|
11743
11921
|
const resolvedPath = path7.resolve(outputPath);
|
|
11744
|
-
|
|
11745
|
-
|
|
11922
|
+
fs12.mkdirSync(path7.dirname(resolvedPath), { recursive: true });
|
|
11923
|
+
fs12.writeFileSync(resolvedPath, bytes);
|
|
11746
11924
|
return resolvedPath;
|
|
11747
11925
|
}
|
|
11748
11926
|
function renderCover(pdf, report) {
|
|
@@ -11901,8 +12079,8 @@ PDF saved: ${savedPdfPath}`);
|
|
|
11901
12079
|
}
|
|
11902
12080
|
function writeSnapshotMarkdown(report, outputPath) {
|
|
11903
12081
|
const resolvedPath = path8.resolve(outputPath);
|
|
11904
|
-
|
|
11905
|
-
|
|
12082
|
+
fs13.mkdirSync(path8.dirname(resolvedPath), { recursive: true });
|
|
12083
|
+
fs13.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
|
|
11906
12084
|
return resolvedPath;
|
|
11907
12085
|
}
|
|
11908
12086
|
function formatSnapshotMarkdown(report) {
|
|
@@ -13130,7 +13308,7 @@ async function bootstrapCommand(_opts) {
|
|
|
13130
13308
|
|
|
13131
13309
|
// src/commands/daemon.ts
|
|
13132
13310
|
import { spawn as spawn2 } from "child_process";
|
|
13133
|
-
import
|
|
13311
|
+
import fs14 from "fs";
|
|
13134
13312
|
import path10 from "path";
|
|
13135
13313
|
function getPidPath() {
|
|
13136
13314
|
return path10.join(getConfigDir(), "canonry.pid");
|
|
@@ -13173,8 +13351,8 @@ function buildServeForwardArgs(opts) {
|
|
|
13173
13351
|
async function startDaemon(opts) {
|
|
13174
13352
|
const pidPath = getPidPath();
|
|
13175
13353
|
const format = opts.format ?? "text";
|
|
13176
|
-
if (
|
|
13177
|
-
const existingPid = parseInt(
|
|
13354
|
+
if (fs14.existsSync(pidPath)) {
|
|
13355
|
+
const existingPid = parseInt(fs14.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
13178
13356
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
13179
13357
|
throw new CliError({
|
|
13180
13358
|
code: "DAEMON_ALREADY_RUNNING",
|
|
@@ -13185,7 +13363,7 @@ async function startDaemon(opts) {
|
|
|
13185
13363
|
}
|
|
13186
13364
|
});
|
|
13187
13365
|
}
|
|
13188
|
-
|
|
13366
|
+
fs14.unlinkSync(pidPath);
|
|
13189
13367
|
}
|
|
13190
13368
|
const cliPath = path10.resolve(new URL(import.meta.url).pathname);
|
|
13191
13369
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
@@ -13204,10 +13382,10 @@ async function startDaemon(opts) {
|
|
|
13204
13382
|
});
|
|
13205
13383
|
}
|
|
13206
13384
|
const configDir = getConfigDir();
|
|
13207
|
-
if (!
|
|
13208
|
-
|
|
13385
|
+
if (!fs14.existsSync(configDir)) {
|
|
13386
|
+
fs14.mkdirSync(configDir, { recursive: true });
|
|
13209
13387
|
}
|
|
13210
|
-
|
|
13388
|
+
fs14.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
13211
13389
|
const port = opts.port ?? "4100";
|
|
13212
13390
|
const host = opts.host ?? "127.0.0.1";
|
|
13213
13391
|
if (!isMachineFormat(format)) {
|
|
@@ -13216,7 +13394,7 @@ async function startDaemon(opts) {
|
|
|
13216
13394
|
const ready = await waitForReady(host, port);
|
|
13217
13395
|
if (!ready) {
|
|
13218
13396
|
try {
|
|
13219
|
-
|
|
13397
|
+
fs14.unlinkSync(pidPath);
|
|
13220
13398
|
} catch {
|
|
13221
13399
|
}
|
|
13222
13400
|
throw new CliError({
|
|
@@ -13248,7 +13426,7 @@ async function startDaemon(opts) {
|
|
|
13248
13426
|
}
|
|
13249
13427
|
function stopDaemon(format = "text") {
|
|
13250
13428
|
const pidPath = getPidPath();
|
|
13251
|
-
if (!
|
|
13429
|
+
if (!fs14.existsSync(pidPath)) {
|
|
13252
13430
|
if (isMachineFormat(format)) {
|
|
13253
13431
|
console.log(JSON.stringify({
|
|
13254
13432
|
stopped: false,
|
|
@@ -13259,7 +13437,7 @@ function stopDaemon(format = "text") {
|
|
|
13259
13437
|
console.log("Canonry is not running (no PID file found)");
|
|
13260
13438
|
return;
|
|
13261
13439
|
}
|
|
13262
|
-
const pid = parseInt(
|
|
13440
|
+
const pid = parseInt(fs14.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
13263
13441
|
if (isNaN(pid)) {
|
|
13264
13442
|
if (isMachineFormat(format)) {
|
|
13265
13443
|
console.log(JSON.stringify({
|
|
@@ -13270,7 +13448,7 @@ function stopDaemon(format = "text") {
|
|
|
13270
13448
|
} else {
|
|
13271
13449
|
console.error("Invalid PID file. Removing it.");
|
|
13272
13450
|
}
|
|
13273
|
-
|
|
13451
|
+
fs14.unlinkSync(pidPath);
|
|
13274
13452
|
return;
|
|
13275
13453
|
}
|
|
13276
13454
|
if (!isProcessAlive(pid)) {
|
|
@@ -13284,12 +13462,12 @@ function stopDaemon(format = "text") {
|
|
|
13284
13462
|
} else {
|
|
13285
13463
|
console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
|
|
13286
13464
|
}
|
|
13287
|
-
|
|
13465
|
+
fs14.unlinkSync(pidPath);
|
|
13288
13466
|
return;
|
|
13289
13467
|
}
|
|
13290
13468
|
try {
|
|
13291
13469
|
process.kill(pid, "SIGTERM");
|
|
13292
|
-
|
|
13470
|
+
fs14.unlinkSync(pidPath);
|
|
13293
13471
|
if (isMachineFormat(format)) {
|
|
13294
13472
|
console.log(JSON.stringify({
|
|
13295
13473
|
stopped: true,
|
|
@@ -13313,7 +13491,7 @@ function stopDaemon(format = "text") {
|
|
|
13313
13491
|
|
|
13314
13492
|
// src/commands/init.ts
|
|
13315
13493
|
import crypto2 from "crypto";
|
|
13316
|
-
import
|
|
13494
|
+
import fs15 from "fs";
|
|
13317
13495
|
import readline2 from "readline";
|
|
13318
13496
|
import path11 from "path";
|
|
13319
13497
|
var pendingServeHandoff = false;
|
|
@@ -13351,7 +13529,7 @@ var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
|
|
|
13351
13529
|
function cwdLooksLikeProject(dir) {
|
|
13352
13530
|
const home = process.env.HOME ?? "";
|
|
13353
13531
|
if (home && path11.resolve(dir) === path11.resolve(home)) return false;
|
|
13354
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
13532
|
+
return PROJECT_MARKERS.some((marker) => fs15.existsSync(path11.join(dir, marker)));
|
|
13355
13533
|
}
|
|
13356
13534
|
var DEFAULT_AGENT_MODELS = {
|
|
13357
13535
|
anthropic: "anthropic/claude-sonnet-4-6",
|
|
@@ -13382,8 +13560,8 @@ async function initCommand(opts) {
|
|
|
13382
13560
|
return void 0;
|
|
13383
13561
|
}
|
|
13384
13562
|
const configDir = getConfigDir();
|
|
13385
|
-
if (!
|
|
13386
|
-
|
|
13563
|
+
if (!fs15.existsSync(configDir)) {
|
|
13564
|
+
fs15.mkdirSync(configDir, { recursive: true });
|
|
13387
13565
|
}
|
|
13388
13566
|
const bootstrapEnv = getBootstrapEnv(process.env, {
|
|
13389
13567
|
GEMINI_API_KEY: opts?.geminiKey,
|
|
@@ -13684,7 +13862,7 @@ function encodeLegacySetupState(state) {
|
|
|
13684
13862
|
}
|
|
13685
13863
|
|
|
13686
13864
|
// src/agent-plugin.ts
|
|
13687
|
-
import
|
|
13865
|
+
import fs16 from "fs";
|
|
13688
13866
|
import path12 from "path";
|
|
13689
13867
|
var CANONRY_PLUGIN_ID = "canonry@canonry";
|
|
13690
13868
|
var REQUIRED_SKILLS = ["canonry", "aero"];
|
|
@@ -13729,7 +13907,7 @@ function isCanonryPluginId(value) {
|
|
|
13729
13907
|
}
|
|
13730
13908
|
function readJson(filePath) {
|
|
13731
13909
|
try {
|
|
13732
|
-
return JSON.parse(
|
|
13910
|
+
return JSON.parse(fs16.readFileSync(filePath, "utf8"));
|
|
13733
13911
|
} catch {
|
|
13734
13912
|
return null;
|
|
13735
13913
|
}
|
|
@@ -13748,7 +13926,7 @@ function readCodexPluginConfigured(filePath) {
|
|
|
13748
13926
|
try {
|
|
13749
13927
|
let currentPlugin = null;
|
|
13750
13928
|
let inPluginsTable = false;
|
|
13751
|
-
for (const line of
|
|
13929
|
+
for (const line of fs16.readFileSync(filePath, "utf8").split(/\r?\n/)) {
|
|
13752
13930
|
const section = /^\s*\[plugins\.(?:"([^"]+)"|'([^']+)'|(\S+))\]\s*(?:#.*)?$/.exec(line);
|
|
13753
13931
|
if (section) {
|
|
13754
13932
|
const captures = section.slice(1, 4);
|
|
@@ -13781,7 +13959,7 @@ function readCodexPluginConfigured(filePath) {
|
|
|
13781
13959
|
}
|
|
13782
13960
|
}
|
|
13783
13961
|
function verifiedPluginVersion(root, client) {
|
|
13784
|
-
if (client === "codex" &&
|
|
13962
|
+
if (client === "codex" && fs16.existsSync(path12.join(root, "plugin.json"))) {
|
|
13785
13963
|
const manifest2 = readJson(path12.join(root, "plugin.json"));
|
|
13786
13964
|
if (manifest2 && typeof manifest2 === "object") {
|
|
13787
13965
|
const plugin2 = manifest2;
|
|
@@ -13795,7 +13973,7 @@ function verifiedPluginVersion(root, client) {
|
|
|
13795
13973
|
if (portableMcp.$schema !== AGENT_PLUGINS_MCP_SCHEMA || portableMcp.mcpServers?.canonry?.type !== "stdio" || portableMcp.mcpServers.canonry.command !== "canonry-mcp") {
|
|
13796
13974
|
return null;
|
|
13797
13975
|
}
|
|
13798
|
-
return REQUIRED_SKILLS.every((name) =>
|
|
13976
|
+
return REQUIRED_SKILLS.every((name) => fs16.existsSync(path12.join(root, "skills", name, "SKILL.md"))) ? plugin2.version : null;
|
|
13799
13977
|
}
|
|
13800
13978
|
if (typeof plugin2.$schema === "string" && plugin2.$schema.startsWith("https://agent-plugins.org/schemas/")) {
|
|
13801
13979
|
return null;
|
|
@@ -13813,7 +13991,7 @@ function verifiedPluginVersion(root, client) {
|
|
|
13813
13991
|
if (!mcp || typeof mcp !== "object") return null;
|
|
13814
13992
|
const canonryServer = mcp.mcpServers?.canonry;
|
|
13815
13993
|
if (canonryServer?.command !== "canonry-mcp") return null;
|
|
13816
|
-
return REQUIRED_SKILLS.every((name) =>
|
|
13994
|
+
return REQUIRED_SKILLS.every((name) => fs16.existsSync(path12.join(root, "skills", name, "SKILL.md"))) ? plugin.version : null;
|
|
13817
13995
|
}
|
|
13818
13996
|
function readClaudeUserInstallPaths(claudeConfigDir) {
|
|
13819
13997
|
const parsed = readJson(path12.join(claudeConfigDir, "plugins", "installed_plugins.json"));
|
|
@@ -13830,7 +14008,7 @@ function readClaudeUserInstallPaths(claudeConfigDir) {
|
|
|
13830
14008
|
}
|
|
13831
14009
|
function listDirectories(dir) {
|
|
13832
14010
|
try {
|
|
13833
|
-
return
|
|
14011
|
+
return fs16.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path12.join(dir, entry.name));
|
|
13834
14012
|
} catch {
|
|
13835
14013
|
return [];
|
|
13836
14014
|
}
|
|
@@ -14354,6 +14532,29 @@ async function technicalAeoTrend(project, opts) {
|
|
|
14354
14532
|
}
|
|
14355
14533
|
console.log(lines.join("\n"));
|
|
14356
14534
|
}
|
|
14535
|
+
async function technicalAeoProgress(project, opts) {
|
|
14536
|
+
const progress = await getClient27().getTechnicalAeoProgress(project, opts.runId);
|
|
14537
|
+
if (isMachineFormat(opts.format)) {
|
|
14538
|
+
console.log(JSON.stringify(progress, null, 2));
|
|
14539
|
+
return;
|
|
14540
|
+
}
|
|
14541
|
+
const lines = [
|
|
14542
|
+
`Site Health progress: ${progress.phase} (${progress.status})`,
|
|
14543
|
+
`Run: ${progress.runId}`
|
|
14544
|
+
];
|
|
14545
|
+
if (progress.attempt) {
|
|
14546
|
+
lines.push(
|
|
14547
|
+
`Pages: ${progress.attempt.pagesDiscovered} found \xB7 ${progress.attempt.pagesFetched} checked \xB7 ${progress.attempt.pagesErrored} failed`,
|
|
14548
|
+
`Eligible: ${progress.attempt.pagesEligible} \xB7 Links found: ${progress.attempt.edgesDiscovered}`,
|
|
14549
|
+
`Updated: ${progress.attempt.lastUpdatedAt}`
|
|
14550
|
+
);
|
|
14551
|
+
} else {
|
|
14552
|
+
lines.push("Pages: waiting for the crawl to start");
|
|
14553
|
+
}
|
|
14554
|
+
lines.push(`Layout: ${progress.layout.state}`);
|
|
14555
|
+
if (progress.error) lines.push(`Error: ${progress.error}`);
|
|
14556
|
+
console.log(lines.join("\n"));
|
|
14557
|
+
}
|
|
14357
14558
|
async function technicalAeoCrawl(project, opts) {
|
|
14358
14559
|
const crawl = await getClient27().getTechnicalAeoCrawl(project, { runId: opts.runId });
|
|
14359
14560
|
if (isMachineFormat(opts.format)) {
|
|
@@ -14848,6 +15049,21 @@ var TECHNICAL_AEO_CLI_COMMANDS_BASE = [
|
|
|
14848
15049
|
await technicalAeoCrawl(project, { runId: getString(input.values, "run-id"), format: input.format });
|
|
14849
15050
|
}
|
|
14850
15051
|
},
|
|
15052
|
+
{
|
|
15053
|
+
path: ["technical-aeo", "progress"],
|
|
15054
|
+
usage: "canonry technical-aeo progress <project> --run-id <id> [--format json]",
|
|
15055
|
+
options: { "run-id": stringOption() },
|
|
15056
|
+
run: async (input) => {
|
|
15057
|
+
const usage = "canonry technical-aeo progress <project> --run-id <id> [--format json]";
|
|
15058
|
+
const project = requireProject(input, "technical-aeo.progress", usage);
|
|
15059
|
+
const runId = requireStringOption(input, "run-id", {
|
|
15060
|
+
command: "technical-aeo.progress",
|
|
15061
|
+
usage,
|
|
15062
|
+
message: "--run-id is required"
|
|
15063
|
+
});
|
|
15064
|
+
await technicalAeoProgress(project, { runId, format: input.format });
|
|
15065
|
+
}
|
|
15066
|
+
},
|
|
14851
15067
|
{
|
|
14852
15068
|
path: ["technical-aeo", "subgraph"],
|
|
14853
15069
|
usage: "canonry technical-aeo subgraph <project> [--run-id <id>] [--node-key <key>|--url <url>] [--hops <n>] [--max-nodes <n>] [--max-edges <n>] [--format json]",
|
|
@@ -15445,7 +15661,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
|
15445
15661
|
];
|
|
15446
15662
|
|
|
15447
15663
|
// src/cli-commands/wordpress.ts
|
|
15448
|
-
import
|
|
15664
|
+
import fs17 from "fs";
|
|
15449
15665
|
|
|
15450
15666
|
// src/commands/wordpress.ts
|
|
15451
15667
|
function getClient28() {
|
|
@@ -15684,12 +15900,12 @@ async function wordpressSetMeta(project, body) {
|
|
|
15684
15900
|
printPageDetail(result);
|
|
15685
15901
|
}
|
|
15686
15902
|
async function wordpressBulkSetMeta(project, opts) {
|
|
15687
|
-
const
|
|
15903
|
+
const fs19 = await import("fs/promises");
|
|
15688
15904
|
const path13 = await import("path");
|
|
15689
15905
|
const filePath = path13.resolve(opts.from);
|
|
15690
15906
|
let raw;
|
|
15691
15907
|
try {
|
|
15692
|
-
raw = await
|
|
15908
|
+
raw = await fs19.readFile(filePath, "utf8");
|
|
15693
15909
|
} catch {
|
|
15694
15910
|
throw new CliError({
|
|
15695
15911
|
code: "FILE_READ_ERROR",
|
|
@@ -15786,13 +16002,13 @@ async function wordpressSetSchema(project, body) {
|
|
|
15786
16002
|
printManualAssist(`Schema update for "${body.slug}"`, result);
|
|
15787
16003
|
}
|
|
15788
16004
|
async function wordpressSchemaDeploy(project, opts) {
|
|
15789
|
-
const
|
|
16005
|
+
const fs19 = await import("fs/promises");
|
|
15790
16006
|
const path13 = await import("path");
|
|
15791
16007
|
const yaml = await loadYamlModule();
|
|
15792
16008
|
const filePath = path13.resolve(opts.profile);
|
|
15793
16009
|
let raw;
|
|
15794
16010
|
try {
|
|
15795
|
-
raw = await
|
|
16011
|
+
raw = await fs19.readFile(filePath, "utf8");
|
|
15796
16012
|
} catch {
|
|
15797
16013
|
throw new CliError({
|
|
15798
16014
|
code: "FILE_READ_ERROR",
|
|
@@ -15897,13 +16113,13 @@ async function wordpressOnboard(project, opts) {
|
|
|
15897
16113
|
}
|
|
15898
16114
|
let profileData;
|
|
15899
16115
|
if (opts.profile) {
|
|
15900
|
-
const
|
|
16116
|
+
const fs19 = await import("fs/promises");
|
|
15901
16117
|
const path13 = await import("path");
|
|
15902
16118
|
const yaml = await loadYamlModule();
|
|
15903
16119
|
const filePath = path13.resolve(opts.profile);
|
|
15904
16120
|
let raw;
|
|
15905
16121
|
try {
|
|
15906
|
-
raw = await
|
|
16122
|
+
raw = await fs19.readFile(filePath, "utf8");
|
|
15907
16123
|
} catch {
|
|
15908
16124
|
throw new CliError({
|
|
15909
16125
|
code: "FILE_READ_ERROR",
|
|
@@ -16052,7 +16268,7 @@ function resolveContent(input, command, usage, options) {
|
|
|
16052
16268
|
}
|
|
16053
16269
|
if (contentFile) {
|
|
16054
16270
|
try {
|
|
16055
|
-
return
|
|
16271
|
+
return fs17.readFileSync(contentFile, "utf-8");
|
|
16056
16272
|
} catch (error) {
|
|
16057
16273
|
const message = error instanceof Error ? error.message : String(error);
|
|
16058
16274
|
throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
|
|
@@ -17019,16 +17235,16 @@ Usage: ${usage}`, {
|
|
|
17019
17235
|
|
|
17020
17236
|
// src/commands/measurement-plan.ts
|
|
17021
17237
|
import crypto3 from "crypto";
|
|
17022
|
-
import
|
|
17238
|
+
import fs18 from "fs";
|
|
17023
17239
|
import { parse } from "yaml";
|
|
17024
17240
|
import { z as z2 } from "zod";
|
|
17025
17241
|
function readPlan(source) {
|
|
17026
|
-
const content = source === "-" ?
|
|
17242
|
+
const content = source === "-" ? fs18.readFileSync(0, "utf8") : fs18.readFileSync(source, "utf8");
|
|
17027
17243
|
const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
|
|
17028
17244
|
return measurementPlanInputSchema.parse(parsed);
|
|
17029
17245
|
}
|
|
17030
17246
|
function readDiscoveryRule(source) {
|
|
17031
|
-
const content = source === "-" ?
|
|
17247
|
+
const content = source === "-" ? fs18.readFileSync(0, "utf8") : fs18.readFileSync(source, "utf8");
|
|
17032
17248
|
const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
|
|
17033
17249
|
return measurementDiscoveryRuleSchema.parse(parsed);
|
|
17034
17250
|
}
|
|
@@ -17077,7 +17293,7 @@ var advancedDeactivateInputSchema = z2.object({
|
|
|
17077
17293
|
}).strict();
|
|
17078
17294
|
function readAdvancedMeasurementInput(source) {
|
|
17079
17295
|
if (source === void 0) return {};
|
|
17080
|
-
const content = source === "-" ?
|
|
17296
|
+
const content = source === "-" ? fs18.readFileSync(0, "utf8") : fs18.readFileSync(source, "utf8");
|
|
17081
17297
|
return JSON.parse(content);
|
|
17082
17298
|
}
|
|
17083
17299
|
var advancedMeasurementCollectionKeys = {
|
|
@@ -17259,7 +17475,7 @@ async function replaceMeasurementPlanAssignments(project, opts) {
|
|
|
17259
17475
|
console.log(JSON.stringify({ preview, result }, null, 2));
|
|
17260
17476
|
}
|
|
17261
17477
|
function readGroupMembershipCsv(source) {
|
|
17262
|
-
return source === "-" ?
|
|
17478
|
+
return source === "-" ? fs18.readFileSync(0, "utf8") : fs18.readFileSync(source, "utf8");
|
|
17263
17479
|
}
|
|
17264
17480
|
async function previewMeasurementPlanGroups(project, source) {
|
|
17265
17481
|
const preview = await createApiClient().previewMeasurementDraftGroupMembership(project, {
|