@canonry/canonry 4.147.0 → 4.148.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.
Files changed (30) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +2 -2
  2. package/assets/assets/{AuditHistoryPanel-DiQ0Ynw5.js → AuditHistoryPanel-D5fRv5sF.js} +1 -1
  3. package/assets/assets/{BacklinksPage-DLUQuPE_.js → BacklinksPage-CFdO1s1V.js} +1 -1
  4. package/assets/assets/{ChartPrimitives-BoEy1qo7.js → ChartPrimitives-BoB1RfNf.js} +1 -1
  5. package/assets/assets/{HistoryPage-mYR2vk8n.js → HistoryPage-YT2JCo2G.js} +1 -1
  6. package/assets/assets/{MeasurementPropertyPage-BocyGHJN.js → MeasurementPropertyPage-JDEzHX1H.js} +1 -1
  7. package/assets/assets/ProjectPage-B6t_j9tN.js +12 -0
  8. package/assets/assets/{RunRow-Ct-A6H9e.js → RunRow-yKrIU8zY.js} +1 -1
  9. package/assets/assets/{RunsPage-CsDtq0Qw.js → RunsPage-DAeC6Ebm.js} +1 -1
  10. package/assets/assets/{SettingsPage-BXwFGc1P.js → SettingsPage-8Z251PH0.js} +1 -1
  11. package/assets/assets/{TrafficPage-B2omyoI8.js → TrafficPage-DNJGp16_.js} +1 -1
  12. package/assets/assets/{TrafficSourceDetailPage-CoEqc6OJ.js → TrafficSourceDetailPage-BuzdNFB8.js} +1 -1
  13. package/assets/assets/{arrow-left-Dh0vsQxe.js → arrow-left-BrVL2J2e.js} +1 -1
  14. package/assets/assets/{extract-error-message-DvWJ0xRn.js → extract-error-message-jd9FdYvE.js} +1 -1
  15. package/assets/assets/index-Bo0hzrG2.js +213 -0
  16. package/assets/assets/{index-CXe6S1ey.css → index-D5NO3NEG.css} +1 -1
  17. package/assets/assets/{trash-2-D1_8ZseY.js → trash-2-lAIhBm6w.js} +1 -1
  18. package/assets/assets/{v2-overview-adapter-owDeFdUc.js → v2-overview-adapter-BHmxTmCf.js} +1 -1
  19. package/assets/index.html +2 -2
  20. package/dist/{chunk-4BL24FQA.js → chunk-3HYF3LUP.js} +353 -346
  21. package/dist/{chunk-BVOU4UJM.js → chunk-43XIYBG4.js} +8 -0
  22. package/dist/{chunk-ZDYS24LW.js → chunk-MHTZ4THA.js} +7 -4
  23. package/dist/{chunk-DRDNHYIF.js → chunk-VUTKHFTM.js} +77 -22
  24. package/dist/cli.js +209 -7
  25. package/dist/index.js +4 -4
  26. package/dist/{intelligence-service-7CGZ537D.js → intelligence-service-OGOGIQJD.js} +2 -2
  27. package/dist/mcp.js +2 -2
  28. package/package.json +8 -8
  29. package/assets/assets/ProjectPage-Q5wQ7nSW.js +0 -12
  30. package/assets/assets/index-FE8JPHmT.js +0 -213
@@ -5436,6 +5436,14 @@ var apiKeyDtoSchema = z9.object({
5436
5436
  * scoped key may only read/write its own project (enforced server-side).
5437
5437
  */
5438
5438
  projectId: z9.string().nullable(),
5439
+ /**
5440
+ * The scoped project's name, or `null` for a full-instance key. Resolved
5441
+ * server-side so a surface listing keys does not have to fetch every project
5442
+ * to turn an id into something a person can read — the id alone cannot answer
5443
+ * "is this key safe to hand to someone", which is the question the list is
5444
+ * usually open to answer. Additive field.
5445
+ */
5446
+ projectName: z9.string().nullable(),
5439
5447
  /**
5440
5448
  * Server-derived convenience flag: `true` when this key is read-only (carries
5441
5449
  * the `read` scope and no write-granting scope), in which case the API rejects
@@ -10,7 +10,7 @@ import {
10
10
  loadConfig,
11
11
  loadConfigRaw,
12
12
  saveConfigPatch
13
- } from "./chunk-4BL24FQA.js";
13
+ } from "./chunk-3HYF3LUP.js";
14
14
  import {
15
15
  CC_CACHE_DIR,
16
16
  DUCKDB_SPEC,
@@ -126,7 +126,7 @@ import {
126
126
  siteAuditSnapshots,
127
127
  toAlertView,
128
128
  usageCounters
129
- } from "./chunk-DRDNHYIF.js";
129
+ } from "./chunk-VUTKHFTM.js";
130
130
  import {
131
131
  AGENT_MEMORY_VALUE_MAX_BYTES,
132
132
  AGENT_PROVIDER_IDS,
@@ -217,7 +217,7 @@ import {
217
217
  validationError,
218
218
  winnabilityClassLabel,
219
219
  withRetry
220
- } from "./chunk-BVOU4UJM.js";
220
+ } from "./chunk-43XIYBG4.js";
221
221
 
222
222
  // src/telemetry.ts
223
223
  import crypto from "crypto";
@@ -7420,7 +7420,7 @@ function readStoredGroundingSources(rawResponse) {
7420
7420
  return result;
7421
7421
  }
7422
7422
  async function backfillInsightsCommand(project, opts) {
7423
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-7CGZ537D.js");
7423
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-OGOGIQJD.js");
7424
7424
  const config = loadConfig();
7425
7425
  const db = createClient(config.database);
7426
7426
  migrate(db);
@@ -13885,6 +13885,9 @@ async function createServer(opts) {
13885
13885
  if (!dashboardShowUpdateNotification) {
13886
13886
  dashboardConfig.showUpdateNotification = false;
13887
13887
  }
13888
+ if (!agentEnabled) {
13889
+ dashboardConfig.showAgentBar = false;
13890
+ }
13888
13891
  if (Object.keys(dashboardConfig).length > 0) {
13889
13892
  clientConfig.dashboard = dashboardConfig;
13890
13893
  }
@@ -517,7 +517,7 @@ import {
517
517
  wordpressSchemaDeployResultDtoSchema,
518
518
  wordpressSchemaStatusResultDtoSchema,
519
519
  wordpressStatusDtoSchema
520
- } from "./chunk-BVOU4UJM.js";
520
+ } from "./chunk-43XIYBG4.js";
521
521
 
522
522
  // src/intelligence-service.ts
523
523
  import { eq as eq57, desc as desc26, asc as asc11, and as and45, ne as ne7, or as or11, inArray as inArray19, gte as gte13, lte as lte10 } from "drizzle-orm";
@@ -5037,6 +5037,20 @@ var MIGRATION_VERSIONS = [
5037
5037
  `CREATE INDEX IF NOT EXISTS idx_measurement_operation_receipts_expires
5038
5038
  ON measurement_operation_receipts(expires_at)`
5039
5039
  ]
5040
+ },
5041
+ {
5042
+ version: 124,
5043
+ name: "measurement-foundation-named-indexes",
5044
+ statements: [
5045
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_measurement_plan_versions_project_revision
5046
+ ON measurement_plan_versions(project_id, revision)`,
5047
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_measurement_plan_versions_project_id
5048
+ ON measurement_plan_versions(project_id, id)`,
5049
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_measurement_segments_project_key
5050
+ ON measurement_segments(project_id, stable_key)`,
5051
+ `CREATE UNIQUE INDEX IF NOT EXISTS idx_measurement_segments_project_id
5052
+ ON measurement_segments(project_id, id)`
5053
+ ]
5040
5054
  }
5041
5055
  ];
5042
5056
  function addRunsMeasurementPlanVersionForeignKey(tx) {
@@ -32713,26 +32727,32 @@ function buildOperationId(method, path8) {
32713
32727
  import crypto22 from "crypto";
32714
32728
  import { desc as desc16, eq as eq35 } from "drizzle-orm";
32715
32729
  var KEYS_WRITE_SCOPE = "keys.write";
32716
- function toApiKeyDto(row) {
32730
+ function toApiKeyDto(row, projectNames) {
32717
32731
  const scopes = Array.isArray(row.scopes) ? row.scopes : [];
32732
+ const projectId = row.projectId ?? null;
32718
32733
  return {
32719
32734
  id: row.id,
32720
32735
  name: row.name,
32721
32736
  keyPrefix: row.keyPrefix,
32722
32737
  scopes,
32723
- projectId: row.projectId ?? null,
32738
+ projectId,
32739
+ projectName: projectId ? projectNames.get(projectId) ?? null : null,
32724
32740
  readOnly: isReadOnlyKey(scopes),
32725
32741
  createdAt: row.createdAt,
32726
32742
  lastUsedAt: row.lastUsedAt ?? null,
32727
32743
  revokedAt: row.revokedAt ?? null
32728
32744
  };
32729
32745
  }
32746
+ function projectNameById(db) {
32747
+ return new Map(db.select().from(projects).all().map((p) => [p.id, p.name]));
32748
+ }
32730
32749
  async function keysRoutes(app) {
32731
32750
  app.get("/keys", async (request) => {
32732
32751
  requireAdminSession(request);
32733
32752
  const scopedProjectId = request.apiKey?.projectId;
32734
32753
  const rows = scopedProjectId ? app.db.select().from(apiKeys).where(eq35(apiKeys.projectId, scopedProjectId)).orderBy(desc16(apiKeys.createdAt)).all() : app.db.select().from(apiKeys).orderBy(desc16(apiKeys.createdAt)).all();
32735
- return { keys: rows.map(toApiKeyDto) };
32754
+ const names = projectNameById(app.db);
32755
+ return { keys: rows.map((row) => toApiKeyDto(row, names)) };
32736
32756
  });
32737
32757
  app.get("/keys/self", async (request) => {
32738
32758
  const id = request.apiKey?.id;
@@ -32743,7 +32763,7 @@ async function keysRoutes(app) {
32743
32763
  if (!row) {
32744
32764
  throw notFound("API key", id);
32745
32765
  }
32746
- return toApiKeyDto(row);
32766
+ return toApiKeyDto(row, projectNameById(app.db));
32747
32767
  });
32748
32768
  app.post("/keys", async (request) => {
32749
32769
  requireAdminSession(request);
@@ -32793,6 +32813,9 @@ async function keysRoutes(app) {
32793
32813
  keyPrefix,
32794
32814
  scopes: effectiveScopes,
32795
32815
  projectId: projectId ?? null,
32816
+ // Resolved from the project the caller just named, so the response says
32817
+ // what the key reaches without a second round trip.
32818
+ projectName: projectId ? projectNameById(app.db).get(projectId) ?? null : null,
32796
32819
  readOnly: isReadOnlyKey(effectiveScopes),
32797
32820
  createdAt: now,
32798
32821
  lastUsedAt: null,
@@ -32817,7 +32840,7 @@ async function keysRoutes(app) {
32817
32840
  throw forbidden("A project-scoped key can only revoke keys scoped to its own project.");
32818
32841
  }
32819
32842
  if (row.revokedAt) {
32820
- return toApiKeyDto(row);
32843
+ return toApiKeyDto(row, projectNameById(app.db));
32821
32844
  }
32822
32845
  const now = (/* @__PURE__ */ new Date()).toISOString();
32823
32846
  app.db.transaction((tx) => {
@@ -32830,7 +32853,7 @@ async function keysRoutes(app) {
32830
32853
  diff: { name: row.name, keyPrefix: row.keyPrefix }
32831
32854
  }));
32832
32855
  });
32833
- return toApiKeyDto({ ...row, revokedAt: now });
32856
+ return toApiKeyDto({ ...row, revokedAt: now }, projectNameById(app.db));
32834
32857
  });
32835
32858
  }
32836
32859
 
@@ -33795,7 +33818,8 @@ async function exchangeCode(clientId, clientSecret, code, redirectUri) {
33795
33818
  detail += detail ? `: ${sanitized}` : sanitized;
33796
33819
  }
33797
33820
  } catch {
33798
- detail = body.length <= 120 ? body : `${body.slice(0, 120)}...`;
33821
+ const truncated = body.length <= 120 ? body : `${body.slice(0, 120)}...`;
33822
+ detail = truncated.replace(new RegExp(escapeRegExp(clientId), "g"), "***").replace(new RegExp(escapeRegExp(clientSecret), "g"), "***").replace(new RegExp(escapeRegExp(code), "g"), "***");
33799
33823
  }
33800
33824
  throw new GoogleAuthError(`Token exchange failed (${res.status}): ${detail}`);
33801
33825
  }
@@ -33833,7 +33857,8 @@ async function refreshAccessToken(clientId, clientSecret, currentRefreshToken) {
33833
33857
  detail += detail ? `: ${sanitized}` : sanitized;
33834
33858
  }
33835
33859
  } catch {
33836
- detail = body.length <= 120 ? body : `${body.slice(0, 120)}...`;
33860
+ const truncated = body.length <= 120 ? body : `${body.slice(0, 120)}...`;
33861
+ detail = truncated.replace(new RegExp(escapeRegExp(clientId), "g"), "***").replace(new RegExp(escapeRegExp(clientSecret), "g"), "***").replace(new RegExp(escapeRegExp(currentRefreshToken), "g"), "***");
33837
33862
  }
33838
33863
  throw new GoogleAuthError(`Token refresh failed (${res.status}): ${detail}`);
33839
33864
  }
@@ -33923,6 +33948,9 @@ function gscClientLog(level, action, ctx) {
33923
33948
  const stream = level === "error" ? process.stderr : process.stdout;
33924
33949
  stream.write(JSON.stringify(entry) + "\n");
33925
33950
  }
33951
+ function escapeRegExp2(str) {
33952
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
33953
+ }
33926
33954
  async function gscFetchResponse(accessToken, url, opts) {
33927
33955
  const method = opts?.method ?? "GET";
33928
33956
  const headers = {
@@ -33947,7 +33975,11 @@ async function gscFetchResponse(accessToken, url, opts) {
33947
33975
  const body = await res.text();
33948
33976
  gscClientLog("error", "http.error", { url, method, httpStatus: res.status });
33949
33977
  const detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
33950
- throw new GoogleApiError(`GSC API error (${res.status}): ${detail}`, res.status);
33978
+ let sanitizedDetail = detail;
33979
+ if (accessToken) {
33980
+ sanitizedDetail = sanitizedDetail.replace(new RegExp(escapeRegExp2(accessToken), "g"), "***");
33981
+ }
33982
+ throw new GoogleApiError(`GSC API error (${res.status}): ${sanitizedDetail}`, res.status);
33951
33983
  }
33952
33984
  return res;
33953
33985
  }
@@ -34206,13 +34238,13 @@ async function getAccessToken(clientEmail, privateKey) {
34206
34238
  const body = await res.text().catch(() => "");
34207
34239
  ga4Log("error", "token.failed", { httpStatus: res.status });
34208
34240
  const detail = body.length <= 200 ? body : `${body.slice(0, 200)}... [truncated]`;
34209
- const sanitizedDetail = detail.replace(new RegExp(escapeRegExp2(clientEmail), "g"), "***").replace(new RegExp(escapeRegExp2(privateKey.slice(0, 32)), "g"), "***");
34241
+ const sanitizedDetail = detail.replace(new RegExp(escapeRegExp3(clientEmail), "g"), "***").replace(new RegExp(escapeRegExp3(privateKey.slice(0, 32)), "g"), "***");
34210
34242
  throw new GA4ApiError(`Failed to get access token: ${sanitizedDetail}`, res.status);
34211
34243
  }
34212
34244
  const data = await res.json();
34213
34245
  return data.access_token;
34214
34246
  }
34215
- function escapeRegExp2(str) {
34247
+ function escapeRegExp3(str) {
34216
34248
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
34217
34249
  }
34218
34250
  var gaInFlight = 0;
@@ -34315,9 +34347,13 @@ async function runReport(accessToken, propertyId, request) {
34315
34347
  } catch {
34316
34348
  if (body.length < 200) detail = ` ${body}`;
34317
34349
  }
34350
+ let sanitizedDetail = detail;
34351
+ if (accessToken) {
34352
+ sanitizedDetail = sanitizedDetail.replace(new RegExp(escapeRegExp3(accessToken), "g"), "***");
34353
+ }
34318
34354
  ga4Log("error", "report.auth-failed", { propertyId, httpStatus: res.status });
34319
34355
  throw new GA4ApiError(
34320
- `GA4 API authentication failed \u2014 check service account permissions.${detail}`,
34356
+ `GA4 API authentication failed \u2014 check service account permissions.${sanitizedDetail}`,
34321
34357
  res.status
34322
34358
  );
34323
34359
  }
@@ -34331,7 +34367,11 @@ async function runReport(accessToken, propertyId, request) {
34331
34367
  const retryAfterSeconds = res.status >= 500 ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
34332
34368
  ga4Log("error", "report.error", { propertyId, httpStatus: res.status, retryAfterSeconds });
34333
34369
  const detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
34334
- throw new GA4ApiError(`GA4 API error (${res.status}): ${detail}`, res.status, retryAfterSeconds);
34370
+ let sanitizedDetail = detail;
34371
+ if (accessToken) {
34372
+ sanitizedDetail = sanitizedDetail.replace(new RegExp(escapeRegExp3(accessToken), "g"), "***");
34373
+ }
34374
+ throw new GA4ApiError(`GA4 API error (${res.status}): ${sanitizedDetail}`, res.status, retryAfterSeconds);
34335
34375
  }
34336
34376
  return await res.json();
34337
34377
  }, "report"));
@@ -34351,8 +34391,12 @@ async function batchRunReports(accessToken, propertyId, requests) {
34351
34391
  if (res.status === 401 || res.status === 403) {
34352
34392
  const body = await res.text().catch(() => "");
34353
34393
  ga4Log("error", "batch-report.auth-failed", { propertyId, httpStatus: res.status });
34394
+ let sanitizedDetail = body;
34395
+ if (accessToken) {
34396
+ sanitizedDetail = sanitizedDetail.replace(new RegExp(escapeRegExp3(accessToken), "g"), "***");
34397
+ }
34354
34398
  throw new GA4ApiError(
34355
- `GA4 API authentication failed \u2014 check service account permissions. ${body}`,
34399
+ `GA4 API authentication failed \u2014 check service account permissions. ${sanitizedDetail}`,
34356
34400
  res.status
34357
34401
  );
34358
34402
  }
@@ -34366,7 +34410,11 @@ async function batchRunReports(accessToken, propertyId, requests) {
34366
34410
  const retryAfterSeconds = res.status >= 500 ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
34367
34411
  ga4Log("error", "batch-report.error", { propertyId, httpStatus: res.status, retryAfterSeconds });
34368
34412
  const detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
34369
- throw new GA4ApiError(`GA4 API error (${res.status}): ${detail}`, res.status, retryAfterSeconds);
34413
+ let sanitizedDetail = detail;
34414
+ if (accessToken) {
34415
+ sanitizedDetail = sanitizedDetail.replace(new RegExp(escapeRegExp3(accessToken), "g"), "***");
34416
+ }
34417
+ throw new GA4ApiError(`GA4 API error (${res.status}): ${sanitizedDetail}`, res.status, retryAfterSeconds);
34370
34418
  }
34371
34419
  const data = await res.json();
34372
34420
  return data.reports;
@@ -41701,7 +41749,7 @@ function bingClientLog(level, action, ctx) {
41701
41749
  const stream = level === "error" ? process.stderr : process.stdout;
41702
41750
  stream.write(JSON.stringify(entry) + "\n");
41703
41751
  }
41704
- function escapeRegExp3(str) {
41752
+ function escapeRegExp4(str) {
41705
41753
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
41706
41754
  }
41707
41755
  async function bingFetch(apiKey, endpoint, opts) {
@@ -41729,7 +41777,7 @@ async function bingFetch(apiKey, endpoint, opts) {
41729
41777
  const body = await res.text();
41730
41778
  bingClientLog("error", "http.error", { endpoint, method, httpStatus: res.status });
41731
41779
  let detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
41732
- detail = detail.replace(new RegExp(escapeRegExp3(apiKey), "g"), "***");
41780
+ detail = detail.replace(new RegExp(escapeRegExp4(apiKey), "g"), "***");
41733
41781
  throw new BingApiError(`Bing API error (${res.status}): ${detail}`, res.status);
41734
41782
  }
41735
41783
  const text2 = await res.text();
@@ -43938,7 +43986,14 @@ async function fetchJson(connection, siteUrl, path8, init) {
43938
43986
  }
43939
43987
  if (!res.ok) {
43940
43988
  const text2 = await res.text().catch(() => "");
43941
- throw new WordpressApiError("UPSTREAM_ERROR", `WordPress API error (${res.status}): ${text2 || res.statusText}`, res.status);
43989
+ let detail = text2 || res.statusText;
43990
+ if (connection.appPassword) {
43991
+ detail = detail.replace(new RegExp(escapeRegExp5(connection.appPassword), "g"), "***");
43992
+ }
43993
+ if (connection.username) {
43994
+ detail = detail.replace(new RegExp(escapeRegExp5(connection.username), "g"), "***");
43995
+ }
43996
+ throw new WordpressApiError("UPSTREAM_ERROR", `WordPress API error (${res.status}): ${detail}`, res.status);
43942
43997
  }
43943
43998
  return {
43944
43999
  body: await res.json(),
@@ -44431,12 +44486,12 @@ var CANONRY_SCHEMA_START = "<!-- canonry:schema:start -->";
44431
44486
  var CANONRY_SCHEMA_END = "<!-- canonry:schema:end -->";
44432
44487
  function stripCanonrySchema(content) {
44433
44488
  const regex = new RegExp(
44434
- `${escapeRegExp4(CANONRY_SCHEMA_START)}[\\s\\S]*?${escapeRegExp4(CANONRY_SCHEMA_END)}`,
44489
+ `${escapeRegExp5(CANONRY_SCHEMA_START)}[\\s\\S]*?${escapeRegExp5(CANONRY_SCHEMA_END)}`,
44435
44490
  "g"
44436
44491
  );
44437
44492
  return content.replace(regex, "").replace(/\n{3,}/g, "\n\n").trim();
44438
44493
  }
44439
- function escapeRegExp4(str) {
44494
+ function escapeRegExp5(str) {
44440
44495
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
44441
44496
  }
44442
44497
  function injectCanonrySchema(content, schemas) {
@@ -44543,7 +44598,7 @@ async function getSchemaStatus(connection, env) {
44543
44598
  const thirdPartySchemas = [];
44544
44599
  if (hasCanonryMarker) {
44545
44600
  const markerRegex = new RegExp(
44546
- `${escapeRegExp4(CANONRY_SCHEMA_START)}([\\s\\S]*?)${escapeRegExp4(CANONRY_SCHEMA_END)}`
44601
+ `${escapeRegExp5(CANONRY_SCHEMA_START)}([\\s\\S]*?)${escapeRegExp5(CANONRY_SCHEMA_END)}`
44547
44602
  );
44548
44603
  const match = markerRegex.exec(rawContent);
44549
44604
  if (match?.[1]) {
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  showFirstRunNotice,
31
31
  trackCliCommandFinished,
32
32
  trackEvent
33
- } from "./chunk-ZDYS24LW.js";
33
+ } from "./chunk-MHTZ4THA.js";
34
34
  import {
35
35
  CliError,
36
36
  EXIT_SYSTEM_ERROR,
@@ -43,12 +43,14 @@ import {
43
43
  isMachineFormat,
44
44
  loadConfig,
45
45
  loadConfigRaw,
46
+ measurementDraftOperationSchema,
46
47
  printCliError,
48
+ runMeasurementDraftAction,
47
49
  saveConfig,
48
50
  saveConfigPatch,
49
51
  systemError,
50
52
  usageError
51
- } from "./chunk-4BL24FQA.js";
53
+ } from "./chunk-3HYF3LUP.js";
52
54
  import {
53
55
  apiKeys,
54
56
  createClient,
@@ -56,7 +58,7 @@ import {
56
58
  projects,
57
59
  queries,
58
60
  renderReportHtml
59
- } from "./chunk-DRDNHYIF.js";
61
+ } from "./chunk-VUTKHFTM.js";
60
62
  import {
61
63
  AdsDeliverySnapshotStatuses,
62
64
  AdsHistoricalCampaignRollupStatuses,
@@ -100,15 +102,27 @@ import {
100
102
  formatMicros,
101
103
  formatRatio,
102
104
  formatRunErrorOneLine,
105
+ measurementChangesQuerySchema,
106
+ measurementDataQualityQuerySchema,
103
107
  measurementDiscoveryRequestSchema,
104
108
  measurementDiscoveryRuleSchema,
109
+ measurementDraftCollectionQuerySchema,
110
+ measurementOverviewQuerySchema,
111
+ measurementPlanDeactivateRequestSchema,
105
112
  measurementPlanInputSchema,
113
+ measurementPortfolioSummaryQuerySchema,
114
+ measurementPropertyCompetitorsQuerySchema,
115
+ measurementPropertyQuestionsQuerySchema,
116
+ measurementQuerySetUpsertRequestSchema,
117
+ measurementQueryTemplateApplyRequestSchema,
118
+ measurementQueryTemplateUpsertRequestSchema,
119
+ measurementQuestionResultQuerySchema,
106
120
  normalizeProjectAliases,
107
121
  notificationEventSchema,
108
122
  providerQuotaPolicySchema,
109
123
  resolveProviderInput,
110
124
  winnabilityClassSchema
111
- } from "./chunk-BVOU4UJM.js";
125
+ } from "./chunk-43XIYBG4.js";
112
126
 
113
127
  // src/cli.ts
114
128
  import { pathToFileURL } from "url";
@@ -7423,16 +7437,21 @@ async function listApiKeys(format) {
7423
7437
  return;
7424
7438
  }
7425
7439
  console.log(
7426
- `${"NAME".padEnd(20)} ${"PREFIX".padEnd(11)} ${"SCOPES".padEnd(20)} ${"CREATED".padEnd(12)} ${"LAST USED".padEnd(12)} STATUS`
7440
+ `${"NAME".padEnd(20)} ${"PREFIX".padEnd(11)} ${"SCOPES".padEnd(20)} ${"REACH".padEnd(18)} ${"CREATED".padEnd(12)} ${"LAST USED".padEnd(12)} STATUS`
7427
7441
  );
7428
7442
  for (const key of keys) {
7429
7443
  const scopes = key.scopes.join(",");
7430
7444
  const lastUsed = key.lastUsedAt ? formatIsoDate(key.lastUsedAt) : "\u2014";
7431
7445
  console.log(
7432
- `${key.name.padEnd(20)} ${key.keyPrefix.padEnd(11)} ${scopes.padEnd(20)} ${formatIsoDate(key.createdAt).padEnd(12)} ${lastUsed.padEnd(12)} ${keyStatus(key)}`
7446
+ `${key.name.padEnd(20)} ${key.keyPrefix.padEnd(11)} ${scopes.padEnd(20)} ${keyReach(key).padEnd(18)} ${formatIsoDate(key.createdAt).padEnd(12)} ${lastUsed.padEnd(12)} ${keyStatus(key)}`
7433
7447
  );
7434
7448
  }
7435
7449
  }
7450
+ function keyReach(key) {
7451
+ if (!key.projectId) return "full instance";
7452
+ if (typeof key.projectName === "string") return key.projectName;
7453
+ return key.projectName === null ? "(deleted project)" : key.projectId.slice(0, 8);
7454
+ }
7436
7455
  async function createApiKey(opts) {
7437
7456
  const explicitScopes = opts.scopes && opts.scopes.length > 0 ? opts.scopes : void 0;
7438
7457
  if (opts.readOnly && explicitScopes) {
@@ -7461,7 +7480,7 @@ async function createApiKey(opts) {
7461
7480
  console.log(` Prefix: ${created.keyPrefix}`);
7462
7481
  console.log(` Scopes: ${created.scopes.join(", ")}`);
7463
7482
  console.log(` Read-only: ${created.readOnly ? "yes" : "no"}`);
7464
- console.log(` Project: ${opts.project ?? "(full instance)"}`);
7483
+ console.log(` Reach: ${keyReach(created)}`);
7465
7484
  console.log("\nSave this now \u2014 it will not be shown again.");
7466
7485
  }
7467
7486
  async function showApiKeySelf(format) {
@@ -7474,6 +7493,7 @@ async function showApiKeySelf(format) {
7474
7493
  console.log(`API key "${key.name}" (${key.keyPrefix})`);
7475
7494
  console.log(` Scopes: ${key.scopes.join(", ")}`);
7476
7495
  console.log(` Read-only: ${key.readOnly ? "yes" : "no"}`);
7496
+ console.log(` Reach: ${keyReach(key)}`);
7477
7497
  console.log(` Status: ${keyStatus(key)}`);
7478
7498
  }
7479
7499
  async function revokeApiKey(id, format) {
@@ -15719,6 +15739,7 @@ Usage: ${usage}`, {
15719
15739
  import crypto3 from "crypto";
15720
15740
  import fs16 from "fs";
15721
15741
  import { parse } from "yaml";
15742
+ import { z as z2 } from "zod";
15722
15743
  function readPlan(source) {
15723
15744
  const content = source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15724
15745
  const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
@@ -15729,6 +15750,171 @@ function readDiscoveryRule(source) {
15729
15750
  const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
15730
15751
  return measurementDiscoveryRuleSchema.parse(parsed);
15731
15752
  }
15753
+ var ADVANCED_MEASUREMENT_OPERATIONS = [
15754
+ "setup",
15755
+ "overview",
15756
+ "portfolio-summary",
15757
+ "property-questions",
15758
+ "question-result",
15759
+ "property-competitors",
15760
+ "changes",
15761
+ "data-quality",
15762
+ "draft",
15763
+ "draft-targets",
15764
+ "draft-assignments",
15765
+ "draft-groups",
15766
+ "draft-action",
15767
+ "deactivate",
15768
+ "query-sets",
15769
+ "query-set-get",
15770
+ "query-set-upsert",
15771
+ "query-set-delete",
15772
+ "query-templates",
15773
+ "query-template-upsert",
15774
+ "query-template-delete",
15775
+ "query-template-apply"
15776
+ ];
15777
+ var advancedIdempotencyKeySchema = z2.string().trim().min(1);
15778
+ var advancedResourceIdSchema = z2.string().trim().min(1);
15779
+ var advancedEmptyInputSchema = z2.object({}).strict();
15780
+ var advancedQuerySetInputSchema = z2.object({ setId: advancedResourceIdSchema }).strict();
15781
+ var advancedQuerySetUpsertInputSchema = advancedQuerySetInputSchema.extend({
15782
+ request: measurementQuerySetUpsertRequestSchema
15783
+ }).strict();
15784
+ var advancedQueryTemplateInputSchema = z2.object({ templateId: advancedResourceIdSchema }).strict();
15785
+ var advancedQueryTemplateUpsertInputSchema = advancedQueryTemplateInputSchema.extend({
15786
+ request: measurementQueryTemplateUpsertRequestSchema
15787
+ }).strict();
15788
+ var advancedQueryTemplateApplyInputSchema = advancedQueryTemplateInputSchema.extend({
15789
+ request: measurementQueryTemplateApplyRequestSchema,
15790
+ idempotencyKey: advancedIdempotencyKeySchema
15791
+ }).strict();
15792
+ var advancedDeactivateInputSchema = z2.object({
15793
+ request: measurementPlanDeactivateRequestSchema,
15794
+ idempotencyKey: advancedIdempotencyKeySchema
15795
+ }).strict();
15796
+ function readAdvancedMeasurementInput(source) {
15797
+ if (source === void 0) return {};
15798
+ const content = source === "-" ? fs16.readFileSync(0, "utf8") : fs16.readFileSync(source, "utf8");
15799
+ return JSON.parse(content);
15800
+ }
15801
+ var advancedMeasurementCollectionKeys = {
15802
+ "draft-targets": "items",
15803
+ "draft-assignments": "items",
15804
+ "draft-groups": "items",
15805
+ "query-sets": "querySets",
15806
+ "query-templates": "templates"
15807
+ };
15808
+ function isAdvancedMeasurementCollectionOperation(operation) {
15809
+ return operation === "draft-targets" || operation === "draft-assignments" || operation === "draft-groups" || operation === "query-sets" || operation === "query-templates";
15810
+ }
15811
+ function emitAdvancedMeasurementJsonl(operation, result) {
15812
+ if (!isAdvancedMeasurementCollectionOperation(operation) || typeof result !== "object" || result === null || Array.isArray(result)) return false;
15813
+ const collectionKey = advancedMeasurementCollectionKeys[operation];
15814
+ const envelope = result;
15815
+ const candidateRows = envelope[collectionKey];
15816
+ if (!Array.isArray(candidateRows)) return false;
15817
+ const context = {};
15818
+ for (const [key, value] of Object.entries(envelope)) {
15819
+ if (key !== collectionKey) context[key] = value;
15820
+ }
15821
+ emitJsonl([{ kind: "measurement-advanced-header", operation, ...context }]);
15822
+ emitJsonl(candidateRows.map((row) => row));
15823
+ return true;
15824
+ }
15825
+ async function runAdvancedMeasurementOperation(project, operation, source, format) {
15826
+ const input = readAdvancedMeasurementInput(source);
15827
+ const client = createApiClient();
15828
+ let result;
15829
+ switch (operation) {
15830
+ case "setup":
15831
+ advancedEmptyInputSchema.parse(input);
15832
+ result = await client.getMeasurementSetup(project);
15833
+ break;
15834
+ case "overview":
15835
+ result = await client.getMeasurementOverview(project, measurementOverviewQuerySchema.parse(input));
15836
+ break;
15837
+ case "portfolio-summary":
15838
+ result = await client.getMeasurementPortfolioSummary(project, measurementPortfolioSummaryQuerySchema.parse(input));
15839
+ break;
15840
+ case "property-questions":
15841
+ result = await client.getMeasurementPropertyQuestions(project, measurementPropertyQuestionsQuerySchema.parse(input));
15842
+ break;
15843
+ case "question-result":
15844
+ result = await client.getMeasurementQuestionResult(project, measurementQuestionResultQuerySchema.parse(input));
15845
+ break;
15846
+ case "property-competitors":
15847
+ result = await client.getMeasurementPropertyCompetitors(project, measurementPropertyCompetitorsQuerySchema.parse(input));
15848
+ break;
15849
+ case "changes":
15850
+ result = await client.getMeasurementChanges(project, measurementChangesQuerySchema.parse(input));
15851
+ break;
15852
+ case "data-quality":
15853
+ result = await client.getMeasurementDataQuality(project, measurementDataQualityQuerySchema.parse(input));
15854
+ break;
15855
+ case "draft":
15856
+ advancedEmptyInputSchema.parse(input);
15857
+ result = await client.getMeasurementPlanDraft(project);
15858
+ break;
15859
+ case "draft-targets":
15860
+ result = await client.getMeasurementDraftTargets(project, measurementDraftCollectionQuerySchema.parse(input));
15861
+ break;
15862
+ case "draft-assignments":
15863
+ result = await client.getMeasurementDraftAssignments(project, measurementDraftCollectionQuerySchema.parse(input));
15864
+ break;
15865
+ case "draft-groups":
15866
+ result = await client.getMeasurementDraftGroups(project, measurementDraftCollectionQuerySchema.parse(input));
15867
+ break;
15868
+ case "draft-action":
15869
+ result = await runMeasurementDraftAction(client, project, measurementDraftOperationSchema.parse(input));
15870
+ break;
15871
+ case "deactivate": {
15872
+ const parsed = advancedDeactivateInputSchema.parse(input);
15873
+ result = await client.deactivateMeasurementPlan(project, parsed.request, parsed.idempotencyKey);
15874
+ break;
15875
+ }
15876
+ case "query-sets":
15877
+ advancedEmptyInputSchema.parse(input);
15878
+ result = await client.listMeasurementQuerySets(project);
15879
+ break;
15880
+ case "query-set-get": {
15881
+ const parsed = advancedQuerySetInputSchema.parse(input);
15882
+ result = await client.getMeasurementQuerySet(project, parsed.setId);
15883
+ break;
15884
+ }
15885
+ case "query-set-upsert": {
15886
+ const parsed = advancedQuerySetUpsertInputSchema.parse(input);
15887
+ result = await client.upsertMeasurementQuerySet(project, parsed.setId, parsed.request);
15888
+ break;
15889
+ }
15890
+ case "query-set-delete": {
15891
+ const parsed = advancedQuerySetInputSchema.parse(input);
15892
+ result = await client.deleteMeasurementQuerySet(project, parsed.setId);
15893
+ break;
15894
+ }
15895
+ case "query-templates":
15896
+ advancedEmptyInputSchema.parse(input);
15897
+ result = await client.listMeasurementQueryTemplates(project);
15898
+ break;
15899
+ case "query-template-upsert": {
15900
+ const parsed = advancedQueryTemplateUpsertInputSchema.parse(input);
15901
+ result = await client.upsertMeasurementQueryTemplate(project, parsed.templateId, parsed.request);
15902
+ break;
15903
+ }
15904
+ case "query-template-delete": {
15905
+ const parsed = advancedQueryTemplateInputSchema.parse(input);
15906
+ result = await client.deleteMeasurementQueryTemplate(project, parsed.templateId);
15907
+ break;
15908
+ }
15909
+ case "query-template-apply": {
15910
+ const parsed = advancedQueryTemplateApplyInputSchema.parse(input);
15911
+ result = await client.applyMeasurementQueryTemplate(project, parsed.templateId, parsed.request, parsed.idempotencyKey);
15912
+ break;
15913
+ }
15914
+ }
15915
+ if (format === "jsonl" && emitAdvancedMeasurementJsonl(operation, result)) return;
15916
+ console.log(JSON.stringify(result ?? null, null, 2));
15917
+ }
15732
15918
  async function showMeasurementPlan(project, revision) {
15733
15919
  const client = createApiClient();
15734
15920
  console.log(JSON.stringify(revision === void 0 ? await client.getMeasurementPlan(project) : await client.getMeasurementPlanVersion(project, revision), null, 2));
@@ -16008,6 +16194,12 @@ Usage: ${usage}`);
16008
16194
  }
16009
16195
  return { project, options: { groupKeys, targetKeys, queryIds, allProperties } };
16010
16196
  }
16197
+ function advancedMeasurementOperation(value, usage) {
16198
+ const operation = ADVANCED_MEASUREMENT_OPERATIONS.find((candidate) => candidate === value);
16199
+ if (operation) return operation;
16200
+ throw usageError(`Error: unsupported Advanced Measurement operation: ${value ?? "(none)"}
16201
+ Usage: ${usage}`);
16202
+ }
16011
16203
  var MEASUREMENT_PLAN_CLI_COMMANDS = [
16012
16204
  { path: ["measurement-plan", "show"], usage: "canonry measurement-plan show <project> [--revision N] [--format json]", options: { revision: stringOption() }, run: async (input) => {
16013
16205
  const value = getString(input.values, "revision");
@@ -16028,6 +16220,16 @@ var MEASUREMENT_PLAN_CLI_COMMANDS = [
16028
16220
  if (!stableKey) throw usageError("stable segment key is required");
16029
16221
  return retireMeasurementPlanSegment(project, stableKey);
16030
16222
  } },
16223
+ {
16224
+ path: ["measurement-plan", "advanced"],
16225
+ usage: "canonry measurement-plan advanced <project> <operation> [<json|->] [--format json|jsonl]",
16226
+ run: (input) => {
16227
+ const usage = "canonry measurement-plan advanced <project> <operation> [<json|->] [--format json|jsonl]";
16228
+ const project = requireProject(input, "measurement-plan.advanced", usage);
16229
+ const operation = advancedMeasurementOperation(input.positionals[1], usage);
16230
+ return runAdvancedMeasurementOperation(project, operation, input.positionals[2], input.format);
16231
+ }
16232
+ },
16031
16233
  {
16032
16234
  path: ["measurement-plan", "assignments", "preview"],
16033
16235
  usage: "canonry measurement-plan assignments preview <project> [--group KEY ...] [--target-key KEY ... | --all-properties] --query-id ID [--query-id ID ...] [--format json]",
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-ZDYS24LW.js";
3
+ } from "./chunk-MHTZ4THA.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-4BL24FQA.js";
7
- import "./chunk-DRDNHYIF.js";
8
- import "./chunk-BVOU4UJM.js";
6
+ } from "./chunk-3HYF3LUP.js";
7
+ import "./chunk-VUTKHFTM.js";
8
+ import "./chunk-43XIYBG4.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-DRDNHYIF.js";
4
- import "./chunk-BVOU4UJM.js";
3
+ } from "./chunk-VUTKHFTM.js";
4
+ import "./chunk-43XIYBG4.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };