@ainyc/canonry 4.180.6 → 4.180.8
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 +4 -0
- package/assets/agent-workspace/skills/canonry/SKILL.md +13 -10
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +7 -6
- package/assets/assets/{AuditHistoryPanel-Cwgbldst.js → AuditHistoryPanel-qiuqNGvG.js} +1 -1
- package/assets/assets/{BacklinksPage-h08vP0Of.js → BacklinksPage-D-g5f0Xv.js} +1 -1
- package/assets/assets/{HistoryPage-Dwyad0V0.js → HistoryPage-q8_pCuOs.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DOyOHeiU.js → MeasurementPropertyPage-C_wMjUZe.js} +1 -1
- package/assets/assets/ProjectPage-33THfDtC.js +9 -0
- package/assets/assets/{RunRow-CVl2cqfG.js → RunRow-D5hatdlY.js} +1 -1
- package/assets/assets/{RunsPage-zzN2iQbk.js → RunsPage-Bj2snMM3.js} +1 -1
- package/assets/assets/SettingsPage-Cf5YgyJv.js +1 -0
- package/assets/assets/SiteHealthSection-D8RLvMAE.js +4 -0
- package/assets/assets/TrafficPage-CotJ14le.js +1 -0
- package/assets/assets/{TrafficSourceDetailPage-BnbNPkis.js → TrafficSourceDetailPage-BcxYX-uq.js} +1 -1
- package/assets/assets/{extract-error-message-Ctp1FqW1.js → extract-error-message-Bxt42scd.js} +1 -1
- package/assets/assets/index-BlILyZJ5.js +86 -0
- package/assets/assets/index-DXCQf5s1.css +1 -0
- package/assets/assets/{react-sigma_core.esm.min-DwnhdseV.js → react-sigma_core.esm.min-DxZINEmi.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-XYTSKRO3.js → chunk-G7M2KM7Q.js} +2 -2
- package/dist/{chunk-VZO6CLHY.js → chunk-GFVZOVG3.js} +105 -64
- package/dist/{chunk-RXXZ5BU5.js → chunk-GN2G7VFK.js} +24 -1
- package/dist/{chunk-CWXPBQR5.js → chunk-IM4HFNGF.js} +7 -5
- package/dist/{chunk-WJFBNCVD.js → chunk-ZJ2VGTYU.js} +197 -95
- package/dist/cli.js +187 -96
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-MEPYXRBS.js → intelligence-service-IURLYRB3.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +10 -10
- package/assets/assets/ProjectPage-D9e_1Gpz.js +0 -9
- package/assets/assets/SettingsPage-qiQLOtpd.js +0 -1
- package/assets/assets/SiteHealthSection-R0MWiuZX.js +0 -4
- package/assets/assets/TrafficPage-CEA76iwx.js +0 -1
- package/assets/assets/index-BD8hYPvq.css +0 -1
- package/assets/assets/index-D-OGmIKF.js +0 -83
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
installSkills,
|
|
6
6
|
loadConfigRaw,
|
|
7
7
|
saveConfigPatch
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-IM4HFNGF.js";
|
|
9
9
|
import {
|
|
10
10
|
SKILL_MANIFEST_FILENAME,
|
|
11
11
|
SkillsClients
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-GN2G7VFK.js";
|
|
13
13
|
|
|
14
14
|
// src/skills-autosync.ts
|
|
15
15
|
import fs from "fs";
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
loadConfig,
|
|
12
12
|
loadConfigRaw,
|
|
13
13
|
saveConfigPatch
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-IM4HFNGF.js";
|
|
15
15
|
import {
|
|
16
16
|
CC_CACHE_DIR,
|
|
17
17
|
DUCKDB_SPEC,
|
|
@@ -157,7 +157,7 @@ import {
|
|
|
157
157
|
siteCrawlSnapshots,
|
|
158
158
|
toAlertView,
|
|
159
159
|
usageCounters
|
|
160
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-ZJ2VGTYU.js";
|
|
161
161
|
import {
|
|
162
162
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
163
163
|
AGENT_PROVIDER_IDS,
|
|
@@ -266,6 +266,7 @@ import {
|
|
|
266
266
|
isSelfLink,
|
|
267
267
|
isVertexGroundingRedirect,
|
|
268
268
|
mapWithConcurrency,
|
|
269
|
+
nextScheduleUpdatedAt,
|
|
269
270
|
normalizeIdTokens,
|
|
270
271
|
normalizeMeasurementExecutionQueryText,
|
|
271
272
|
normalizeServedModel,
|
|
@@ -295,7 +296,7 @@ import {
|
|
|
295
296
|
validationError,
|
|
296
297
|
winnabilityClassLabel,
|
|
297
298
|
withRetry
|
|
298
|
-
} from "./chunk-
|
|
299
|
+
} from "./chunk-GN2G7VFK.js";
|
|
299
300
|
|
|
300
301
|
// src/telemetry.ts
|
|
301
302
|
import crypto from "crypto";
|
|
@@ -11866,7 +11867,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
11866
11867
|
return result;
|
|
11867
11868
|
}
|
|
11868
11869
|
async function backfillInsightsCommand(project, opts) {
|
|
11869
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
11870
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-IURLYRB3.js");
|
|
11870
11871
|
const config = loadConfig();
|
|
11871
11872
|
const db = createClient(config.database);
|
|
11872
11873
|
migrate(db);
|
|
@@ -12447,6 +12448,21 @@ import cron from "node-cron";
|
|
|
12447
12448
|
import { and as and14, eq as eq17, inArray as inArray6, notExists, sql as sql8 } from "drizzle-orm";
|
|
12448
12449
|
var log14 = createLogger("Scheduler");
|
|
12449
12450
|
var DEFAULT_HEALTH_CRON = "0 */6 * * *";
|
|
12451
|
+
function ensureDefaultHealthSchedule(db, projectId, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
12452
|
+
const result = db.insert(schedules).values({
|
|
12453
|
+
id: crypto20.randomUUID(),
|
|
12454
|
+
projectId,
|
|
12455
|
+
kind: SchedulableRunKinds.doctor,
|
|
12456
|
+
cronExpr: DEFAULT_HEALTH_CRON,
|
|
12457
|
+
timezone: "UTC",
|
|
12458
|
+
enabled: true,
|
|
12459
|
+
providers: [],
|
|
12460
|
+
nextRunAt: nextRunFromCron(DEFAULT_HEALTH_CRON, "UTC"),
|
|
12461
|
+
createdAt: now,
|
|
12462
|
+
updatedAt: now
|
|
12463
|
+
}).onConflictDoNothing().run();
|
|
12464
|
+
return result.changes === 1;
|
|
12465
|
+
}
|
|
12450
12466
|
function taskKey(projectId, kind) {
|
|
12451
12467
|
return `${projectId}::${kind}`;
|
|
12452
12468
|
}
|
|
@@ -12483,21 +12499,13 @@ var Scheduler = class {
|
|
|
12483
12499
|
)).all();
|
|
12484
12500
|
if (projectsWithoutHealth.length === 0) return;
|
|
12485
12501
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12502
|
+
let seeded = 0;
|
|
12486
12503
|
for (const project of projectsWithoutHealth) {
|
|
12487
|
-
this.db.
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
cronExpr: DEFAULT_HEALTH_CRON,
|
|
12492
|
-
timezone: "UTC",
|
|
12493
|
-
enabled: true,
|
|
12494
|
-
providers: [],
|
|
12495
|
-
nextRunAt: nextRunFromCron(DEFAULT_HEALTH_CRON, "UTC"),
|
|
12496
|
-
createdAt: now,
|
|
12497
|
-
updatedAt: now
|
|
12498
|
-
}).run();
|
|
12504
|
+
if (ensureDefaultHealthSchedule(this.db, project.id, now)) seeded += 1;
|
|
12505
|
+
}
|
|
12506
|
+
if (seeded > 0) {
|
|
12507
|
+
log14.info("health-schedule.seeded", { projectCount: seeded, cron: DEFAULT_HEALTH_CRON });
|
|
12499
12508
|
}
|
|
12500
|
-
log14.info("health-schedule.seeded", { projectCount: projectsWithoutHealth.length, cron: DEFAULT_HEALTH_CRON });
|
|
12501
12509
|
}
|
|
12502
12510
|
/**
|
|
12503
12511
|
* Record each project's current query set as basket revision 1 if it has
|
|
@@ -12584,6 +12592,17 @@ var Scheduler = class {
|
|
|
12584
12592
|
void task.destroy();
|
|
12585
12593
|
log14.info(`task.${verb.toLowerCase()}`, { key });
|
|
12586
12594
|
}
|
|
12595
|
+
/** Runtime timing writes must not restore a version already issued to a settings caller. */
|
|
12596
|
+
updateScheduleTiming(scheduleId, timing) {
|
|
12597
|
+
this.db.transaction((tx) => {
|
|
12598
|
+
const current = tx.select({ updatedAt: schedules.updatedAt }).from(schedules).where(eq17(schedules.id, scheduleId)).get();
|
|
12599
|
+
if (!current) return;
|
|
12600
|
+
tx.update(schedules).set({
|
|
12601
|
+
...timing,
|
|
12602
|
+
updatedAt: nextScheduleUpdatedAt(current.updatedAt)
|
|
12603
|
+
}).where(eq17(schedules.id, scheduleId)).run();
|
|
12604
|
+
});
|
|
12605
|
+
}
|
|
12587
12606
|
registerCronTask(schedule) {
|
|
12588
12607
|
const { id: scheduleId, projectId, cronExpr, timezone } = schedule;
|
|
12589
12608
|
const kind = schedule.kind;
|
|
@@ -12597,10 +12616,9 @@ var Scheduler = class {
|
|
|
12597
12616
|
timezone
|
|
12598
12617
|
});
|
|
12599
12618
|
this.tasks.set(taskKey(projectId, kind), task);
|
|
12600
|
-
this.
|
|
12601
|
-
nextRunAt: nextRunFromCron(cronExpr, timezone)
|
|
12602
|
-
|
|
12603
|
-
}).where(eq17(schedules.id, scheduleId)).run();
|
|
12619
|
+
this.updateScheduleTiming(scheduleId, {
|
|
12620
|
+
nextRunAt: nextRunFromCron(cronExpr, timezone)
|
|
12621
|
+
});
|
|
12604
12622
|
const label = schedule.preset ?? cronExpr;
|
|
12605
12623
|
log14.info("cron.registered", { projectId, kind, schedule: label, timezone });
|
|
12606
12624
|
}
|
|
@@ -12630,11 +12648,10 @@ var Scheduler = class {
|
|
|
12630
12648
|
log14.warn("traffic-sync.no-callback", { scheduleId, projectId, msg: "host did not register onTrafficSyncRequested" });
|
|
12631
12649
|
return;
|
|
12632
12650
|
}
|
|
12633
|
-
this.
|
|
12651
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12634
12652
|
lastRunAt: now,
|
|
12635
|
-
nextRunAt
|
|
12636
|
-
|
|
12637
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12653
|
+
nextRunAt
|
|
12654
|
+
});
|
|
12638
12655
|
log14.info("traffic-sync.triggered", { projectName: project.name, sourceId });
|
|
12639
12656
|
this.callbacks.onTrafficSyncRequested(project.name, sourceId);
|
|
12640
12657
|
return;
|
|
@@ -12653,11 +12670,10 @@ var Scheduler = class {
|
|
|
12653
12670
|
trigger: RunTriggers.scheduled,
|
|
12654
12671
|
createdAt: now
|
|
12655
12672
|
}).run();
|
|
12656
|
-
this.
|
|
12673
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12657
12674
|
lastRunAt: now,
|
|
12658
|
-
nextRunAt
|
|
12659
|
-
|
|
12660
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12675
|
+
nextRunAt
|
|
12676
|
+
});
|
|
12661
12677
|
log14.info("gbp-sync.triggered", { runId: runId2, projectName: project.name });
|
|
12662
12678
|
this.callbacks.onGbpSyncRequested(runId2, projectId);
|
|
12663
12679
|
return;
|
|
@@ -12674,7 +12690,7 @@ var Scheduler = class {
|
|
|
12674
12690
|
)).get();
|
|
12675
12691
|
if (activeAdsRun) {
|
|
12676
12692
|
log14.info("ads-sync.skipped-active", { projectName: project.name, activeRunId: activeAdsRun.id });
|
|
12677
|
-
this.
|
|
12693
|
+
this.updateScheduleTiming(currentSchedule.id, { nextRunAt });
|
|
12678
12694
|
return;
|
|
12679
12695
|
}
|
|
12680
12696
|
const runId2 = crypto20.randomUUID();
|
|
@@ -12686,11 +12702,10 @@ var Scheduler = class {
|
|
|
12686
12702
|
trigger: RunTriggers.scheduled,
|
|
12687
12703
|
createdAt: now
|
|
12688
12704
|
}).run();
|
|
12689
|
-
this.
|
|
12705
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12690
12706
|
lastRunAt: now,
|
|
12691
|
-
nextRunAt
|
|
12692
|
-
|
|
12693
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12707
|
+
nextRunAt
|
|
12708
|
+
});
|
|
12694
12709
|
log14.info("ads-sync.triggered", { runId: runId2, projectName: project.name });
|
|
12695
12710
|
this.callbacks.onAdsSyncRequested(runId2, projectId);
|
|
12696
12711
|
return;
|
|
@@ -12700,11 +12715,10 @@ var Scheduler = class {
|
|
|
12700
12715
|
log14.warn("data-refresh.no-callback", { scheduleId, projectId, msg: "host did not register onDataRefreshRequested" });
|
|
12701
12716
|
return;
|
|
12702
12717
|
}
|
|
12703
|
-
this.
|
|
12718
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12704
12719
|
lastRunAt: now,
|
|
12705
|
-
nextRunAt
|
|
12706
|
-
|
|
12707
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12720
|
+
nextRunAt
|
|
12721
|
+
});
|
|
12708
12722
|
log14.info("data-refresh.triggered", { projectName: project.name });
|
|
12709
12723
|
this.callbacks.onDataRefreshRequested(project.name);
|
|
12710
12724
|
return;
|
|
@@ -12714,11 +12728,10 @@ var Scheduler = class {
|
|
|
12714
12728
|
log14.warn("doctor.no-callback", { scheduleId, projectId, msg: "host did not register onDoctorRequested" });
|
|
12715
12729
|
return;
|
|
12716
12730
|
}
|
|
12717
|
-
this.
|
|
12731
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12718
12732
|
lastRunAt: now,
|
|
12719
|
-
nextRunAt
|
|
12720
|
-
|
|
12721
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12733
|
+
nextRunAt
|
|
12734
|
+
});
|
|
12722
12735
|
log14.info("doctor.triggered", { projectName: project.name });
|
|
12723
12736
|
this.callbacks.onDoctorRequested(project.name);
|
|
12724
12737
|
return;
|
|
@@ -12728,11 +12741,10 @@ var Scheduler = class {
|
|
|
12728
12741
|
log14.warn("backlinks-sync.no-callback", { scheduleId, projectId, msg: "host did not register onBacklinksSyncRequested" });
|
|
12729
12742
|
return;
|
|
12730
12743
|
}
|
|
12731
|
-
this.
|
|
12744
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12732
12745
|
lastRunAt: now,
|
|
12733
|
-
nextRunAt
|
|
12734
|
-
|
|
12735
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12746
|
+
nextRunAt
|
|
12747
|
+
});
|
|
12736
12748
|
log14.info("backlinks-sync.triggered", { projectName: project.name });
|
|
12737
12749
|
this.callbacks.onBacklinksSyncRequested(project.name);
|
|
12738
12750
|
return;
|
|
@@ -12749,7 +12761,7 @@ var Scheduler = class {
|
|
|
12749
12761
|
)).get();
|
|
12750
12762
|
if (active) {
|
|
12751
12763
|
log14.info("site-audit.skipped-active", { projectName: project.name, activeRunId: active.id });
|
|
12752
|
-
this.
|
|
12764
|
+
this.updateScheduleTiming(currentSchedule.id, { nextRunAt });
|
|
12753
12765
|
return;
|
|
12754
12766
|
}
|
|
12755
12767
|
const runId2 = crypto20.randomUUID();
|
|
@@ -12771,11 +12783,10 @@ var Scheduler = class {
|
|
|
12771
12783
|
createdAt: now
|
|
12772
12784
|
}).run();
|
|
12773
12785
|
});
|
|
12774
|
-
this.
|
|
12786
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12775
12787
|
lastRunAt: now,
|
|
12776
|
-
nextRunAt
|
|
12777
|
-
|
|
12778
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12788
|
+
nextRunAt
|
|
12789
|
+
});
|
|
12779
12790
|
log14.info("site-audit.triggered", { runId: runId2, projectName: project.name });
|
|
12780
12791
|
this.callbacks.onSiteAuditRequested(runId2, projectId);
|
|
12781
12792
|
return;
|
|
@@ -12805,18 +12816,16 @@ var Scheduler = class {
|
|
|
12805
12816
|
});
|
|
12806
12817
|
if (queueResult.conflict) {
|
|
12807
12818
|
log14.info("run.skipped-active", { projectName: project.name, activeRunId: queueResult.activeRunId });
|
|
12808
|
-
this.
|
|
12809
|
-
nextRunAt
|
|
12810
|
-
|
|
12811
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12819
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12820
|
+
nextRunAt
|
|
12821
|
+
});
|
|
12812
12822
|
return;
|
|
12813
12823
|
}
|
|
12814
12824
|
const runId = queueResult.runId;
|
|
12815
|
-
this.
|
|
12825
|
+
this.updateScheduleTiming(currentSchedule.id, {
|
|
12816
12826
|
lastRunAt: now,
|
|
12817
|
-
nextRunAt
|
|
12818
|
-
|
|
12819
|
-
}).where(eq17(schedules.id, currentSchedule.id)).run();
|
|
12827
|
+
nextRunAt
|
|
12828
|
+
});
|
|
12820
12829
|
log14.info("run.triggered", { runId, projectName: project.name, providers: providers ?? "all" });
|
|
12821
12830
|
this.callbacks.onRunCreated(runId, projectId, providers, resolvedLocation);
|
|
12822
12831
|
} catch (err) {
|
|
@@ -16775,6 +16784,11 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
|
|
|
16775
16784
|
var _require3 = createRequire4(import.meta.url);
|
|
16776
16785
|
var { version: PKG_VERSION2 } = _require3("../package.json");
|
|
16777
16786
|
var log21 = createLogger("Server");
|
|
16787
|
+
var runtimeStartupByServer = /* @__PURE__ */ new WeakMap();
|
|
16788
|
+
function waitForServerRuntimeStartup(app) {
|
|
16789
|
+
const startup = runtimeStartupByServer.get(app);
|
|
16790
|
+
return startup ?? Promise.reject(new Error("Server runtime startup was not registered"));
|
|
16791
|
+
}
|
|
16778
16792
|
var DEFAULT_QUOTA = {
|
|
16779
16793
|
maxConcurrency: 2,
|
|
16780
16794
|
maxRequestsPerMinute: 10,
|
|
@@ -18114,7 +18128,7 @@ async function createServer(opts) {
|
|
|
18114
18128
|
return reply.status(401).send({
|
|
18115
18129
|
error: {
|
|
18116
18130
|
code: "AUTH_INVALID",
|
|
18117
|
-
message: "Server API key not found \u2014
|
|
18131
|
+
message: "Server API key not found \u2014 run canonry bootstrap"
|
|
18118
18132
|
}
|
|
18119
18133
|
});
|
|
18120
18134
|
}
|
|
@@ -18679,6 +18693,11 @@ async function createServer(opts) {
|
|
|
18679
18693
|
if (action === "upsert") scheduler.upsert(projectId, kind);
|
|
18680
18694
|
if (action === "delete") scheduler.remove(projectId, kind);
|
|
18681
18695
|
},
|
|
18696
|
+
onProjectCreated: (projectId) => {
|
|
18697
|
+
if (ensureDefaultHealthSchedule(opts.db, projectId)) {
|
|
18698
|
+
scheduler.upsert(projectId, SchedulableRunKinds.doctor);
|
|
18699
|
+
}
|
|
18700
|
+
},
|
|
18682
18701
|
onProjectDeleting: prepareGoogleMarketingCredentialDelete,
|
|
18683
18702
|
onProjectDeleted: (projectId) => {
|
|
18684
18703
|
scheduler.removeAllForProject(projectId);
|
|
@@ -18948,10 +18967,30 @@ async function createServer(opts) {
|
|
|
18948
18967
|
app.get(`${basePath}health`, healthHandler);
|
|
18949
18968
|
}
|
|
18950
18969
|
checkLatestVersionForServer();
|
|
18951
|
-
|
|
18952
|
-
|
|
18953
|
-
|
|
18954
|
-
|
|
18970
|
+
let resolveRuntimeStartup;
|
|
18971
|
+
let rejectRuntimeStartup;
|
|
18972
|
+
const runtimeStartup = new Promise((resolve, reject) => {
|
|
18973
|
+
resolveRuntimeStartup = resolve;
|
|
18974
|
+
rejectRuntimeStartup = reject;
|
|
18975
|
+
});
|
|
18976
|
+
void runtimeStartup.catch(() => {
|
|
18977
|
+
});
|
|
18978
|
+
runtimeStartupByServer.set(app, runtimeStartup);
|
|
18979
|
+
let runtimeStartupSettled = false;
|
|
18980
|
+
app.addHook("onListen", () => {
|
|
18981
|
+
if (runtimeStartupSettled) return;
|
|
18982
|
+
try {
|
|
18983
|
+
scheduler.start();
|
|
18984
|
+
for (const run of opts.db.select({ id: researchRuns.id, projectId: researchRuns.projectId }).from(researchRuns).where(eq26(researchRuns.status, ResearchRunStatuses.queued)).all()) {
|
|
18985
|
+
dispatchResearchRun(run.id, run.projectId);
|
|
18986
|
+
}
|
|
18987
|
+
runtimeStartupSettled = true;
|
|
18988
|
+
resolveRuntimeStartup();
|
|
18989
|
+
} catch (error) {
|
|
18990
|
+
runtimeStartupSettled = true;
|
|
18991
|
+
rejectRuntimeStartup(error);
|
|
18992
|
+
}
|
|
18993
|
+
});
|
|
18955
18994
|
app.addHook("onClose", async () => {
|
|
18956
18995
|
scheduler.stop();
|
|
18957
18996
|
});
|
|
@@ -19043,5 +19082,7 @@ export {
|
|
|
19043
19082
|
GoogleMarketingRuntimeError,
|
|
19044
19083
|
createGoogleMarketingCredentialStore,
|
|
19045
19084
|
createGoogleMarketingRuntime,
|
|
19085
|
+
waitForServerRuntimeStartup,
|
|
19086
|
+
isLoopbackBindHost,
|
|
19046
19087
|
createServer
|
|
19047
19088
|
};
|
|
@@ -78,6 +78,14 @@ function runInProgress(projectName) {
|
|
|
78
78
|
function operationInProgress(message, details) {
|
|
79
79
|
return new AppError("OPERATION_IN_PROGRESS", message, 409, details);
|
|
80
80
|
}
|
|
81
|
+
function scheduleVersionConflict(expectedUpdatedAt, actualUpdatedAt) {
|
|
82
|
+
return new AppError(
|
|
83
|
+
"SCHEDULE_VERSION_CONFLICT",
|
|
84
|
+
"The schedule changed since it was loaded. Reload it before saving.",
|
|
85
|
+
409,
|
|
86
|
+
{ expectedUpdatedAt, actualUpdatedAt }
|
|
87
|
+
);
|
|
88
|
+
}
|
|
81
89
|
function measurementPlanRevisionConflict(expectedActiveRevision, actualActiveRevision) {
|
|
82
90
|
return new AppError(
|
|
83
91
|
"MEASUREMENT_PLAN_REVISION_CONFLICT",
|
|
@@ -6818,6 +6826,8 @@ var measurementSetupResponseSchema = z15.object({
|
|
|
6818
6826
|
state: measurementSetupStateSchema,
|
|
6819
6827
|
nextAction: measurementSetupNextActionSchema,
|
|
6820
6828
|
mode: measurementSetupModeSchema,
|
|
6829
|
+
/** Whether this project's selected provider roster contains an engine the host can execute now. */
|
|
6830
|
+
answerVisibilityProviderReady: z15.boolean(),
|
|
6821
6831
|
activeRevision: measurementDraftRevisionSchema.nullable(),
|
|
6822
6832
|
activeSchemaVersion: z15.union([z15.literal(1), z15.literal(2)]).nullable(),
|
|
6823
6833
|
draft: z15.object({
|
|
@@ -10748,6 +10758,11 @@ var scheduleDtoSchema = z31.object({
|
|
|
10748
10758
|
createdAt: z31.string(),
|
|
10749
10759
|
updatedAt: z31.string()
|
|
10750
10760
|
});
|
|
10761
|
+
var scheduleExpectedUpdatedAtSchema = z31.string().datetime();
|
|
10762
|
+
function nextScheduleUpdatedAt(previous, nowMs = Date.now()) {
|
|
10763
|
+
const previousMs = previous === void 0 ? Number.NaN : Date.parse(previous);
|
|
10764
|
+
return new Date(Number.isFinite(previousMs) ? Math.max(nowMs, previousMs + 1) : nowMs).toISOString();
|
|
10765
|
+
}
|
|
10751
10766
|
var scheduleUpsertRequestSchema = z31.object({
|
|
10752
10767
|
/** Run kind. Defaults to 'answer-visibility' so existing callers don't have to change. */
|
|
10753
10768
|
kind: schedulableRunKindSchema.optional(),
|
|
@@ -10757,7 +10772,12 @@ var scheduleUpsertRequestSchema = z31.object({
|
|
|
10757
10772
|
enabled: z31.boolean().optional().default(true),
|
|
10758
10773
|
providers: z31.array(providerNameSchema).optional().default([]),
|
|
10759
10774
|
/** Required when kind === 'traffic-sync'. Forbidden for other kinds. Validated server-side. */
|
|
10760
|
-
sourceId: z31.string().optional()
|
|
10775
|
+
sourceId: z31.string().optional(),
|
|
10776
|
+
/**
|
|
10777
|
+
* Optimistic concurrency guard. A timestamp updates only that exact version;
|
|
10778
|
+
* null creates only while the schedule is absent. Omit for legacy behavior.
|
|
10779
|
+
*/
|
|
10780
|
+
expectedUpdatedAt: scheduleExpectedUpdatedAtSchema.nullable().optional()
|
|
10761
10781
|
}).refine(
|
|
10762
10782
|
(data) => data.preset && !data.cron || !data.preset && data.cron,
|
|
10763
10783
|
{ message: 'Exactly one of "preset" or "cron" must be provided' }
|
|
@@ -16436,6 +16456,7 @@ export {
|
|
|
16436
16456
|
noQueries,
|
|
16437
16457
|
runInProgress,
|
|
16438
16458
|
operationInProgress,
|
|
16459
|
+
scheduleVersionConflict,
|
|
16439
16460
|
measurementPlanRevisionConflict,
|
|
16440
16461
|
measurementCompiledChecksumConflict,
|
|
16441
16462
|
measurementRunRevisionMismatch,
|
|
@@ -16854,6 +16875,8 @@ export {
|
|
|
16854
16875
|
schedulableRunKindSchema,
|
|
16855
16876
|
SchedulableRunKinds,
|
|
16856
16877
|
scheduleDtoSchema,
|
|
16878
|
+
scheduleExpectedUpdatedAtSchema,
|
|
16879
|
+
nextScheduleUpdatedAt,
|
|
16857
16880
|
scheduleUpsertRequestSchema,
|
|
16858
16881
|
categorizeSource,
|
|
16859
16882
|
categorizeSourceWithCompetitors,
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
trafficConnectWordpressRequestSchema,
|
|
93
93
|
trafficEventKindSchema,
|
|
94
94
|
trafficSeriesGranularitySchema
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-GN2G7VFK.js";
|
|
96
96
|
|
|
97
97
|
// src/config.ts
|
|
98
98
|
import fs from "fs";
|
|
@@ -160,8 +160,8 @@ function loadConfig() {
|
|
|
160
160
|
if (!fs.existsSync(configPath)) {
|
|
161
161
|
throw new Error(
|
|
162
162
|
`Config not found at ${configPath}.
|
|
163
|
-
Run "canonry
|
|
164
|
-
|
|
163
|
+
Run "canonry bootstrap" to create the local Page Health runtime; provider credentials are optional.
|
|
164
|
+
Use "canonry init" instead only when you want interactive provider/OAuth provisioning.`
|
|
165
165
|
);
|
|
166
166
|
}
|
|
167
167
|
const raw = fs.readFileSync(configPath, "utf-8");
|
|
@@ -174,8 +174,10 @@ For CI/Docker, use "canonry bootstrap" with env vars (GEMINI_API_KEY, OPENAI_API
|
|
|
174
174
|
].filter(Boolean).join(", ");
|
|
175
175
|
throw new Error(
|
|
176
176
|
`Invalid config at ${configPath} \u2014 missing: ${missing}.
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
Back up this config privately before you repair it.
|
|
178
|
+
Restore the missing values from a known-good backup. If none exists, recover the original values before you retry.
|
|
179
|
+
Keep the original API key and database path. Do not share secrets.
|
|
180
|
+
Do not use "canonry init --force" for recovery. It replaces credentials without a backup.`
|
|
179
181
|
);
|
|
180
182
|
}
|
|
181
183
|
if (parsed.geminiApiKey && !parsed.providers?.gemini) {
|