@ainyc/canonry 2.5.1 → 2.6.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/assets/assets/{index-agELvqT1.js → index-BsNi8T7D.js} +102 -102
- package/assets/index.html +1 -1
- package/bin/canonry-mcp.mjs +2 -0
- package/dist/chunk-3DUTT6H2.js +2144 -0
- package/dist/{chunk-CFS35BKX.js → chunk-LF4O276A.js} +208 -2168
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/{chunk-32YTAZBL.js → chunk-PYHANJ3B.js} +3 -5
- package/dist/cli.js +23 -20
- package/dist/index.js +6 -3
- package/dist/{intelligence-service-U7YQ4NXV.js → intelligence-service-2ZABHNR4.js} +2 -1
- package/dist/mcp.js +781 -0
- package/package.json +6 -4
|
@@ -1,3 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGENT_MEMORY_KEY_MAX_LENGTH,
|
|
3
|
+
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
4
|
+
AGENT_PROVIDER_IDS,
|
|
5
|
+
AgentProviderIds,
|
|
6
|
+
ApiClient,
|
|
7
|
+
AppError,
|
|
8
|
+
CcReleaseSyncStatuses,
|
|
9
|
+
MemorySources,
|
|
10
|
+
RunKinds,
|
|
11
|
+
RunStatuses,
|
|
12
|
+
RunTriggers,
|
|
13
|
+
agentBusy,
|
|
14
|
+
agentMemoryDeleteRequestSchema,
|
|
15
|
+
agentMemoryUpsertRequestSchema,
|
|
16
|
+
authInvalid,
|
|
17
|
+
authRequired,
|
|
18
|
+
brandKeyFromText,
|
|
19
|
+
categorizeSource,
|
|
20
|
+
categoryLabel,
|
|
21
|
+
configExists,
|
|
22
|
+
deliveryFailed,
|
|
23
|
+
determineAnswerMentioned,
|
|
24
|
+
effectiveDomains,
|
|
25
|
+
extractAnswerMentions,
|
|
26
|
+
findDuplicateLocationLabels,
|
|
27
|
+
hasLocationLabel,
|
|
28
|
+
internalError,
|
|
29
|
+
isAgentProviderId,
|
|
30
|
+
isBrowserProvider,
|
|
31
|
+
loadConfig,
|
|
32
|
+
locationContextSchema,
|
|
33
|
+
missingDependency,
|
|
34
|
+
normalizeProjectDomain,
|
|
35
|
+
notFound,
|
|
36
|
+
notImplemented,
|
|
37
|
+
parseWindow,
|
|
38
|
+
projectConfigSchema,
|
|
39
|
+
projectUpsertRequestSchema,
|
|
40
|
+
providerError,
|
|
41
|
+
runInProgress,
|
|
42
|
+
runNotCancellable,
|
|
43
|
+
runTriggerRequestSchema,
|
|
44
|
+
saveConfigPatch,
|
|
45
|
+
scheduleUpsertRequestSchema,
|
|
46
|
+
snapshotRequestSchema,
|
|
47
|
+
unsupportedKind,
|
|
48
|
+
validationError,
|
|
49
|
+
visibilityStateFromAnswerMentioned,
|
|
50
|
+
windowCutoff,
|
|
51
|
+
wordpressEnvSchema
|
|
52
|
+
} from "./chunk-3DUTT6H2.js";
|
|
1
53
|
import {
|
|
2
54
|
IntelligenceService,
|
|
3
55
|
agentMemory,
|
|
@@ -30,172 +82,7 @@ import {
|
|
|
30
82
|
runs,
|
|
31
83
|
schedules,
|
|
32
84
|
usageCounters
|
|
33
|
-
} from "./chunk-
|
|
34
|
-
|
|
35
|
-
// src/config.ts
|
|
36
|
-
import fs from "fs";
|
|
37
|
-
import path from "path";
|
|
38
|
-
import os from "os";
|
|
39
|
-
import { parse, stringify } from "yaml";
|
|
40
|
-
function normalizeGoogleConfig(config) {
|
|
41
|
-
if (!config.google) return;
|
|
42
|
-
config.google.connections = (config.google.connections ?? []).map((connection) => ({
|
|
43
|
-
...connection,
|
|
44
|
-
propertyId: connection.propertyId ?? null,
|
|
45
|
-
refreshToken: connection.refreshToken ?? null,
|
|
46
|
-
tokenExpiresAt: connection.tokenExpiresAt ?? null,
|
|
47
|
-
scopes: connection.scopes ?? []
|
|
48
|
-
}));
|
|
49
|
-
}
|
|
50
|
-
function normalizeWordpressConfig(config) {
|
|
51
|
-
if (!config.wordpress) return;
|
|
52
|
-
config.wordpress.connections = (config.wordpress.connections ?? []).map((connection) => ({
|
|
53
|
-
...connection,
|
|
54
|
-
url: connection.url.replace(/\/$/, ""),
|
|
55
|
-
stagingUrl: connection.stagingUrl?.replace(/\/$/, ""),
|
|
56
|
-
defaultEnv: connection.defaultEnv ?? "live"
|
|
57
|
-
}));
|
|
58
|
-
}
|
|
59
|
-
function getConfigDir() {
|
|
60
|
-
const override = process.env.CANONRY_CONFIG_DIR?.trim();
|
|
61
|
-
if (override) {
|
|
62
|
-
return override;
|
|
63
|
-
}
|
|
64
|
-
return path.join(os.homedir(), ".canonry");
|
|
65
|
-
}
|
|
66
|
-
function getConfigPath() {
|
|
67
|
-
return path.join(getConfigDir(), "config.yaml");
|
|
68
|
-
}
|
|
69
|
-
function loadConfig() {
|
|
70
|
-
const configPath = getConfigPath();
|
|
71
|
-
if (!fs.existsSync(configPath)) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
`Config not found at ${configPath}.
|
|
74
|
-
Run "canonry init" to set up interactively, or "canonry init --gemini-key <key>" for non-interactive setup.
|
|
75
|
-
For CI/Docker, use "canonry bootstrap" with env vars (GEMINI_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, PERPLEXITY_API_KEY, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET).`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
const raw = fs.readFileSync(configPath, "utf-8");
|
|
79
|
-
const parsed = parse(raw);
|
|
80
|
-
if (!parsed.apiUrl || !parsed.database || !parsed.apiKey) {
|
|
81
|
-
const missing = [
|
|
82
|
-
!parsed.apiUrl && "apiUrl",
|
|
83
|
-
!parsed.database && "database",
|
|
84
|
-
!parsed.apiKey && "apiKey"
|
|
85
|
-
].filter(Boolean).join(", ");
|
|
86
|
-
throw new Error(
|
|
87
|
-
`Invalid config at ${configPath} \u2014 missing: ${missing}.
|
|
88
|
-
These fields are auto-generated. Run "canonry init" (or "canonry init --gemini-key <key>" for non-interactive setup) to create a valid config.
|
|
89
|
-
Do not write config.yaml by hand; use "canonry init", "canonry settings", or "canonry bootstrap" instead.`
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
if (parsed.geminiApiKey && !parsed.providers?.gemini) {
|
|
93
|
-
parsed.providers = {
|
|
94
|
-
...parsed.providers,
|
|
95
|
-
gemini: {
|
|
96
|
-
apiKey: parsed.geminiApiKey,
|
|
97
|
-
model: parsed.geminiModel,
|
|
98
|
-
quota: parsed.geminiQuota
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
normalizeGoogleConfig(parsed);
|
|
103
|
-
normalizeWordpressConfig(parsed);
|
|
104
|
-
const portOverride = process.env.CANONRY_PORT?.trim();
|
|
105
|
-
if (portOverride) {
|
|
106
|
-
try {
|
|
107
|
-
const url = new URL(parsed.apiUrl);
|
|
108
|
-
url.port = portOverride;
|
|
109
|
-
parsed.apiUrl = url.origin;
|
|
110
|
-
} catch {
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if ("CANONRY_BASE_PATH" in process.env) {
|
|
114
|
-
const val = process.env.CANONRY_BASE_PATH.trim();
|
|
115
|
-
parsed.basePath = val || void 0;
|
|
116
|
-
}
|
|
117
|
-
if (parsed.basePath) {
|
|
118
|
-
const normalizedBase = "/" + parsed.basePath.replace(/^\/|\/$/g, "");
|
|
119
|
-
try {
|
|
120
|
-
const url = new URL(parsed.apiUrl);
|
|
121
|
-
if (normalizedBase !== "/" && !url.pathname.startsWith(normalizedBase)) {
|
|
122
|
-
parsed.apiUrl = url.origin + normalizedBase;
|
|
123
|
-
}
|
|
124
|
-
} catch {
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return parsed;
|
|
128
|
-
}
|
|
129
|
-
function loadConfigRaw() {
|
|
130
|
-
const configPath = getConfigPath();
|
|
131
|
-
if (!fs.existsSync(configPath)) return null;
|
|
132
|
-
try {
|
|
133
|
-
return parse(fs.readFileSync(configPath, "utf-8")) ?? null;
|
|
134
|
-
} catch {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function saveConfig(config) {
|
|
139
|
-
const configDir = getConfigDir();
|
|
140
|
-
if (!fs.existsSync(configDir)) {
|
|
141
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
142
|
-
}
|
|
143
|
-
const configPath = getConfigPath();
|
|
144
|
-
const onDisk = loadConfigRaw();
|
|
145
|
-
const merged = onDisk ? { ...onDisk } : {};
|
|
146
|
-
for (const [key, value] of Object.entries(config)) {
|
|
147
|
-
if (value !== void 0) {
|
|
148
|
-
merged[key] = value;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (onDisk) {
|
|
152
|
-
if (process.env.CANONRY_PORT?.trim() || onDisk.basePath) {
|
|
153
|
-
merged.apiUrl = onDisk.apiUrl;
|
|
154
|
-
}
|
|
155
|
-
if ("CANONRY_BASE_PATH" in process.env) {
|
|
156
|
-
if (onDisk.basePath !== void 0) {
|
|
157
|
-
merged.basePath = onDisk.basePath;
|
|
158
|
-
} else {
|
|
159
|
-
delete merged.basePath;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
const yaml = stringify(merged);
|
|
164
|
-
fs.writeFileSync(configPath, yaml, { encoding: "utf-8", mode: 384 });
|
|
165
|
-
}
|
|
166
|
-
function saveConfigPatch(patch) {
|
|
167
|
-
const configDir = getConfigDir();
|
|
168
|
-
if (!fs.existsSync(configDir)) {
|
|
169
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
170
|
-
}
|
|
171
|
-
const configPath = getConfigPath();
|
|
172
|
-
let base = {};
|
|
173
|
-
if (fs.existsSync(configPath)) {
|
|
174
|
-
try {
|
|
175
|
-
const raw = fs.readFileSync(configPath, "utf-8");
|
|
176
|
-
base = parse(raw) ?? {};
|
|
177
|
-
} catch {
|
|
178
|
-
base = {};
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const merged = { ...base, ...patch };
|
|
182
|
-
if (base.database) merged.database = base.database;
|
|
183
|
-
if (base.apiKey) merged.apiKey = base.apiKey;
|
|
184
|
-
if (base.anonymousId) merged.anonymousId = base.anonymousId;
|
|
185
|
-
if (base.dashboardPasswordHash) merged.dashboardPasswordHash = base.dashboardPasswordHash;
|
|
186
|
-
if (base.providers && patch.providers) {
|
|
187
|
-
merged.providers = { ...base.providers };
|
|
188
|
-
for (const [key, patchEntry] of Object.entries(patch.providers)) {
|
|
189
|
-
const baseEntry = base.providers[key] ?? {};
|
|
190
|
-
merged.providers[key] = { ...baseEntry, ...patchEntry };
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
const yaml = stringify(merged);
|
|
194
|
-
fs.writeFileSync(configPath, yaml, { encoding: "utf-8", mode: 384 });
|
|
195
|
-
}
|
|
196
|
-
function configExists() {
|
|
197
|
-
return fs.existsSync(getConfigPath());
|
|
198
|
-
}
|
|
85
|
+
} from "./chunk-PYHANJ3B.js";
|
|
199
86
|
|
|
200
87
|
// src/telemetry.ts
|
|
201
88
|
import crypto from "crypto";
|
|
@@ -261,1266 +148,22 @@ function trackEvent(event, properties) {
|
|
|
261
148
|
const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
262
149
|
timeout.unref();
|
|
263
150
|
fetch(TELEMETRY_ENDPOINT, {
|
|
264
|
-
method: "POST",
|
|
265
|
-
headers: { "Content-Type": "application/json" },
|
|
266
|
-
body: JSON.stringify(payload),
|
|
267
|
-
signal: controller.signal
|
|
268
|
-
}).catch(() => {
|
|
269
|
-
}).finally(() => clearTimeout(timeout));
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// src/
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
constructor(options) {
|
|
281
|
-
super(options.message);
|
|
282
|
-
this.name = "CliError";
|
|
283
|
-
this.code = options.code;
|
|
284
|
-
this.displayMessage = options.displayMessage;
|
|
285
|
-
this.details = options.details;
|
|
286
|
-
this.exitCode = options.exitCode ?? EXIT_USER_ERROR;
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
function usageError(displayMessage, options) {
|
|
290
|
-
const firstLine = displayMessage.split("\n", 1)[0] ?? "Error: invalid command usage";
|
|
291
|
-
return new CliError({
|
|
292
|
-
code: "CLI_USAGE_ERROR",
|
|
293
|
-
message: options?.message ?? firstLine.replace(/^Error:\s*/, ""),
|
|
294
|
-
displayMessage,
|
|
295
|
-
details: options?.details
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
function isEndpointMissing(err) {
|
|
299
|
-
if (!(err instanceof CliError)) return false;
|
|
300
|
-
const status = err.details?.httpStatus;
|
|
301
|
-
return status === 404 || status === 405;
|
|
302
|
-
}
|
|
303
|
-
function printCliError(err, format) {
|
|
304
|
-
if (format === "json") {
|
|
305
|
-
if (err instanceof CliError) {
|
|
306
|
-
console.error(
|
|
307
|
-
JSON.stringify(
|
|
308
|
-
{
|
|
309
|
-
error: {
|
|
310
|
-
code: err.code,
|
|
311
|
-
message: err.message,
|
|
312
|
-
...err.details ? { details: err.details } : {}
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
null,
|
|
316
|
-
2
|
|
317
|
-
)
|
|
318
|
-
);
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
const message = err instanceof Error ? err.message : "An unexpected error occurred";
|
|
322
|
-
console.error(
|
|
323
|
-
JSON.stringify(
|
|
324
|
-
{
|
|
325
|
-
error: {
|
|
326
|
-
code: "CLI_ERROR",
|
|
327
|
-
message
|
|
328
|
-
}
|
|
329
|
-
},
|
|
330
|
-
null,
|
|
331
|
-
2
|
|
332
|
-
)
|
|
333
|
-
);
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
if (err instanceof CliError && err.displayMessage) {
|
|
337
|
-
console.error(err.displayMessage);
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
if (err instanceof Error) {
|
|
341
|
-
console.error(`Error: ${err.message}`);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
console.error("An unexpected error occurred");
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// src/server.ts
|
|
348
|
-
import { createRequire as createRequire3 } from "module";
|
|
349
|
-
import crypto28 from "crypto";
|
|
350
|
-
import fs13 from "fs";
|
|
351
|
-
import path15 from "path";
|
|
352
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
353
|
-
import { eq as eq30 } from "drizzle-orm";
|
|
354
|
-
import Fastify from "fastify";
|
|
355
|
-
|
|
356
|
-
// ../contracts/src/config-schema.ts
|
|
357
|
-
import { z as z4 } from "zod";
|
|
358
|
-
|
|
359
|
-
// ../contracts/src/provider.ts
|
|
360
|
-
import { z } from "zod";
|
|
361
|
-
var providerQuotaPolicySchema = z.object({
|
|
362
|
-
maxConcurrency: z.number().int().positive(),
|
|
363
|
-
maxRequestsPerMinute: z.number().int().positive(),
|
|
364
|
-
maxRequestsPerDay: z.number().int().positive()
|
|
365
|
-
});
|
|
366
|
-
var ProviderNames = {
|
|
367
|
-
gemini: "gemini",
|
|
368
|
-
openai: "openai",
|
|
369
|
-
claude: "claude",
|
|
370
|
-
perplexity: "perplexity",
|
|
371
|
-
local: "local",
|
|
372
|
-
cdpChatgpt: "cdp:chatgpt"
|
|
373
|
-
};
|
|
374
|
-
var providerNameSchema = z.string().min(1);
|
|
375
|
-
var apiProviderNameSchema = z.string().min(1);
|
|
376
|
-
function isBrowserProvider(name) {
|
|
377
|
-
return name.startsWith("cdp:");
|
|
378
|
-
}
|
|
379
|
-
var CDP_TARGETS = ["cdp:chatgpt"];
|
|
380
|
-
function resolveProviderInput(input) {
|
|
381
|
-
const lower = input.trim().toLowerCase();
|
|
382
|
-
if (lower === "cdp") {
|
|
383
|
-
return [...CDP_TARGETS];
|
|
384
|
-
}
|
|
385
|
-
return lower ? [lower] : [];
|
|
386
|
-
}
|
|
387
|
-
var locationContextSchema = z.object({
|
|
388
|
-
label: z.string().min(1),
|
|
389
|
-
city: z.string().min(1),
|
|
390
|
-
region: z.string().min(1),
|
|
391
|
-
country: z.string().length(2),
|
|
392
|
-
timezone: z.string().optional()
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
// ../contracts/src/notification.ts
|
|
396
|
-
import { z as z2 } from "zod";
|
|
397
|
-
var notificationEventSchema = z2.enum([
|
|
398
|
-
"citation.lost",
|
|
399
|
-
"citation.gained",
|
|
400
|
-
"run.completed",
|
|
401
|
-
"run.failed",
|
|
402
|
-
"insight.critical",
|
|
403
|
-
"insight.high"
|
|
404
|
-
]);
|
|
405
|
-
var notificationDtoSchema = z2.object({
|
|
406
|
-
id: z2.string(),
|
|
407
|
-
projectId: z2.string(),
|
|
408
|
-
channel: z2.literal("webhook"),
|
|
409
|
-
url: z2.string().url(),
|
|
410
|
-
urlDisplay: z2.string(),
|
|
411
|
-
urlHost: z2.string(),
|
|
412
|
-
events: z2.array(notificationEventSchema),
|
|
413
|
-
enabled: z2.boolean().default(true),
|
|
414
|
-
/** Opaque tag identifying the creator (e.g. `"agent"` for Aero webhooks). */
|
|
415
|
-
source: z2.string().optional(),
|
|
416
|
-
webhookSecret: z2.string().optional(),
|
|
417
|
-
createdAt: z2.string(),
|
|
418
|
-
updatedAt: z2.string()
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// ../contracts/src/project.ts
|
|
422
|
-
import { z as z3 } from "zod";
|
|
423
|
-
var configSourceSchema = z3.enum(["cli", "api", "config-file"]);
|
|
424
|
-
function findDuplicateLocationLabels(locations) {
|
|
425
|
-
const seen = /* @__PURE__ */ new Set();
|
|
426
|
-
const duplicates = /* @__PURE__ */ new Set();
|
|
427
|
-
for (const location of locations) {
|
|
428
|
-
if (seen.has(location.label)) {
|
|
429
|
-
duplicates.add(location.label);
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
seen.add(location.label);
|
|
433
|
-
}
|
|
434
|
-
return [...duplicates];
|
|
435
|
-
}
|
|
436
|
-
function hasLocationLabel(locations, label) {
|
|
437
|
-
if (!label) return true;
|
|
438
|
-
return locations.some((location) => location.label === label);
|
|
439
|
-
}
|
|
440
|
-
var projectUpsertRequestSchema = z3.object({
|
|
441
|
-
displayName: z3.string().min(1),
|
|
442
|
-
canonicalDomain: z3.string().min(1),
|
|
443
|
-
ownedDomains: z3.array(z3.string().min(1)).optional(),
|
|
444
|
-
country: z3.string().length(2),
|
|
445
|
-
language: z3.string().min(2),
|
|
446
|
-
tags: z3.array(z3.string()).optional(),
|
|
447
|
-
labels: z3.record(z3.string(), z3.string()).optional(),
|
|
448
|
-
providers: z3.array(providerNameSchema).optional(),
|
|
449
|
-
locations: z3.array(locationContextSchema).optional(),
|
|
450
|
-
defaultLocation: z3.string().nullable().optional(),
|
|
451
|
-
autoExtractBacklinks: z3.boolean().optional(),
|
|
452
|
-
configSource: configSourceSchema.optional()
|
|
453
|
-
});
|
|
454
|
-
var projectDtoSchema = z3.object({
|
|
455
|
-
id: z3.string(),
|
|
456
|
-
name: z3.string(),
|
|
457
|
-
displayName: z3.string().optional(),
|
|
458
|
-
canonicalDomain: z3.string(),
|
|
459
|
-
ownedDomains: z3.array(z3.string()).default([]),
|
|
460
|
-
country: z3.string().length(2),
|
|
461
|
-
language: z3.string().min(2),
|
|
462
|
-
tags: z3.array(z3.string()).default([]),
|
|
463
|
-
labels: z3.record(z3.string(), z3.string()).default({}),
|
|
464
|
-
locations: z3.array(locationContextSchema).default([]),
|
|
465
|
-
defaultLocation: z3.string().nullable().optional(),
|
|
466
|
-
autoExtractBacklinks: z3.boolean().default(false),
|
|
467
|
-
configSource: configSourceSchema.default("cli"),
|
|
468
|
-
configRevision: z3.number().int().positive().default(1),
|
|
469
|
-
createdAt: z3.string().optional(),
|
|
470
|
-
updatedAt: z3.string().optional()
|
|
471
|
-
});
|
|
472
|
-
function normalizeProjectDomain(input) {
|
|
473
|
-
let domain = input.trim().toLowerCase();
|
|
474
|
-
try {
|
|
475
|
-
if (domain.includes("://")) {
|
|
476
|
-
domain = new URL(domain).hostname.toLowerCase();
|
|
477
|
-
}
|
|
478
|
-
} catch {
|
|
479
|
-
}
|
|
480
|
-
return domain.replace(/^www\./, "");
|
|
481
|
-
}
|
|
482
|
-
function effectiveDomains(project) {
|
|
483
|
-
const all = [project.canonicalDomain, ...project.ownedDomains ?? []];
|
|
484
|
-
const seen = /* @__PURE__ */ new Set();
|
|
485
|
-
const result = [];
|
|
486
|
-
for (const d of all) {
|
|
487
|
-
const trimmed = d.trim();
|
|
488
|
-
if (!trimmed) continue;
|
|
489
|
-
const norm = normalizeProjectDomain(trimmed);
|
|
490
|
-
if (seen.has(norm)) continue;
|
|
491
|
-
seen.add(norm);
|
|
492
|
-
result.push(trimmed);
|
|
493
|
-
}
|
|
494
|
-
return result;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// ../contracts/src/config-schema.ts
|
|
498
|
-
var configMetadataSchema = z4.object({
|
|
499
|
-
name: z4.string().min(1).max(63).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, {
|
|
500
|
-
message: "Name must be a lowercase slug (letters, numbers, hyphens)"
|
|
501
|
-
}),
|
|
502
|
-
labels: z4.record(z4.string(), z4.string()).optional().default({})
|
|
503
|
-
});
|
|
504
|
-
var configScheduleSchema = z4.object({
|
|
505
|
-
preset: z4.string().optional(),
|
|
506
|
-
cron: z4.string().optional(),
|
|
507
|
-
timezone: z4.string().optional().default("UTC"),
|
|
508
|
-
providers: z4.array(providerNameSchema).optional().default([])
|
|
509
|
-
}).refine(
|
|
510
|
-
(data) => data.preset && !data.cron || !data.preset && data.cron,
|
|
511
|
-
{ message: 'Exactly one of "preset" or "cron" must be provided' }
|
|
512
|
-
).optional();
|
|
513
|
-
var configNotificationSchema = z4.object({
|
|
514
|
-
channel: z4.literal("webhook"),
|
|
515
|
-
url: z4.string().url(),
|
|
516
|
-
events: z4.array(notificationEventSchema).min(1)
|
|
517
|
-
});
|
|
518
|
-
var configGoogleSchema = z4.object({
|
|
519
|
-
gsc: z4.object({
|
|
520
|
-
propertyUrl: z4.string()
|
|
521
|
-
}).optional(),
|
|
522
|
-
syncSchedule: z4.object({
|
|
523
|
-
preset: z4.string().optional(),
|
|
524
|
-
cron: z4.string().optional()
|
|
525
|
-
}).optional()
|
|
526
|
-
}).optional();
|
|
527
|
-
var configSpecSchema = z4.object({
|
|
528
|
-
displayName: z4.string().min(1),
|
|
529
|
-
canonicalDomain: z4.string().min(1),
|
|
530
|
-
ownedDomains: z4.array(z4.string().min(1)).optional().default([]),
|
|
531
|
-
country: z4.string().length(2),
|
|
532
|
-
language: z4.string().min(2),
|
|
533
|
-
keywords: z4.array(z4.string().min(1)).optional().default([]),
|
|
534
|
-
competitors: z4.array(z4.string().min(1)).optional().default([]),
|
|
535
|
-
providers: z4.array(providerNameSchema).optional().default([]),
|
|
536
|
-
locations: z4.array(locationContextSchema).optional().default([]),
|
|
537
|
-
defaultLocation: z4.string().optional(),
|
|
538
|
-
schedule: configScheduleSchema,
|
|
539
|
-
notifications: z4.array(configNotificationSchema).optional().default([]),
|
|
540
|
-
google: configGoogleSchema,
|
|
541
|
-
autoExtractBacklinks: z4.boolean().optional().default(false)
|
|
542
|
-
}).superRefine((spec, ctx) => {
|
|
543
|
-
const duplicateLabels = findDuplicateLocationLabels(spec.locations);
|
|
544
|
-
if (duplicateLabels.length > 0) {
|
|
545
|
-
ctx.addIssue({
|
|
546
|
-
code: "custom",
|
|
547
|
-
message: `Duplicate location labels are not allowed: ${duplicateLabels.join(", ")}`,
|
|
548
|
-
path: ["locations"]
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
if (!hasLocationLabel(spec.locations, spec.defaultLocation)) {
|
|
552
|
-
ctx.addIssue({
|
|
553
|
-
code: "custom",
|
|
554
|
-
message: `defaultLocation "${spec.defaultLocation}" must match a configured location label`,
|
|
555
|
-
path: ["defaultLocation"]
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
var projectConfigSchema = z4.object({
|
|
560
|
-
apiVersion: z4.literal("canonry/v1"),
|
|
561
|
-
kind: z4.literal("Project"),
|
|
562
|
-
metadata: configMetadataSchema,
|
|
563
|
-
spec: configSpecSchema
|
|
564
|
-
});
|
|
565
|
-
|
|
566
|
-
// ../contracts/src/errors.ts
|
|
567
|
-
var AppError = class extends Error {
|
|
568
|
-
code;
|
|
569
|
-
statusCode;
|
|
570
|
-
details;
|
|
571
|
-
constructor(code, message, statusCode, details) {
|
|
572
|
-
super(message);
|
|
573
|
-
this.name = "AppError";
|
|
574
|
-
this.code = code;
|
|
575
|
-
this.statusCode = statusCode;
|
|
576
|
-
this.details = details;
|
|
577
|
-
}
|
|
578
|
-
toJSON() {
|
|
579
|
-
return {
|
|
580
|
-
error: {
|
|
581
|
-
code: this.code,
|
|
582
|
-
message: this.message,
|
|
583
|
-
...this.details ? { details: this.details } : {}
|
|
584
|
-
}
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
function notFound(entity, id) {
|
|
589
|
-
return new AppError("NOT_FOUND", `${entity} '${id}' not found`, 404);
|
|
590
|
-
}
|
|
591
|
-
function validationError(message, details) {
|
|
592
|
-
return new AppError("VALIDATION_ERROR", message, 400, details);
|
|
593
|
-
}
|
|
594
|
-
function authRequired() {
|
|
595
|
-
return new AppError("AUTH_REQUIRED", "Authentication required", 401);
|
|
596
|
-
}
|
|
597
|
-
function authInvalid() {
|
|
598
|
-
return new AppError("AUTH_INVALID", "Invalid API key", 401);
|
|
599
|
-
}
|
|
600
|
-
function providerError(message, details) {
|
|
601
|
-
return new AppError("PROVIDER_ERROR", message, 502, details);
|
|
602
|
-
}
|
|
603
|
-
function runInProgress(projectName) {
|
|
604
|
-
return new AppError("RUN_IN_PROGRESS", `A run is already in progress for '${projectName}'`, 409);
|
|
605
|
-
}
|
|
606
|
-
function runNotCancellable(runId, status) {
|
|
607
|
-
return new AppError("RUN_NOT_CANCELLABLE", `Run '${runId}' is already in terminal state '${status}' and cannot be cancelled`, 409);
|
|
608
|
-
}
|
|
609
|
-
function unsupportedKind(kind) {
|
|
610
|
-
return new AppError("UNSUPPORTED_KIND", `Kind '${kind}' is not supported in this version`, 400);
|
|
611
|
-
}
|
|
612
|
-
function notImplemented(message) {
|
|
613
|
-
return new AppError("NOT_IMPLEMENTED", message, 501);
|
|
614
|
-
}
|
|
615
|
-
function deliveryFailed(message) {
|
|
616
|
-
return new AppError("DELIVERY_FAILED", message, 502);
|
|
617
|
-
}
|
|
618
|
-
function agentBusy(projectName) {
|
|
619
|
-
return new AppError(
|
|
620
|
-
"AGENT_BUSY",
|
|
621
|
-
`Aero is already running a turn for '${projectName}'. Retry after the current turn settles.`,
|
|
622
|
-
409
|
|
623
|
-
);
|
|
624
|
-
}
|
|
625
|
-
function missingDependency(message, details) {
|
|
626
|
-
return new AppError("MISSING_DEPENDENCY", message, 422, details);
|
|
627
|
-
}
|
|
628
|
-
function internalError(message, details) {
|
|
629
|
-
return new AppError("INTERNAL_ERROR", message, 500, details);
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// ../contracts/src/google.ts
|
|
633
|
-
import { z as z5 } from "zod";
|
|
634
|
-
var googleConnectionTypeSchema = z5.enum(["gsc", "ga4"]);
|
|
635
|
-
var googleConnectionDtoSchema = z5.object({
|
|
636
|
-
id: z5.string(),
|
|
637
|
-
domain: z5.string(),
|
|
638
|
-
connectionType: googleConnectionTypeSchema,
|
|
639
|
-
propertyId: z5.string().nullable().optional(),
|
|
640
|
-
sitemapUrl: z5.string().nullable().optional(),
|
|
641
|
-
scopes: z5.array(z5.string()).default([]),
|
|
642
|
-
createdAt: z5.string(),
|
|
643
|
-
updatedAt: z5.string()
|
|
644
|
-
});
|
|
645
|
-
var gscSearchDataDtoSchema = z5.object({
|
|
646
|
-
date: z5.string(),
|
|
647
|
-
query: z5.string(),
|
|
648
|
-
page: z5.string(),
|
|
649
|
-
country: z5.string().nullable().optional(),
|
|
650
|
-
device: z5.string().nullable().optional(),
|
|
651
|
-
clicks: z5.number(),
|
|
652
|
-
impressions: z5.number(),
|
|
653
|
-
ctr: z5.number(),
|
|
654
|
-
position: z5.number()
|
|
655
|
-
});
|
|
656
|
-
var gscUrlInspectionDtoSchema = z5.object({
|
|
657
|
-
id: z5.string(),
|
|
658
|
-
url: z5.string(),
|
|
659
|
-
indexingState: z5.string().nullable().optional(),
|
|
660
|
-
verdict: z5.string().nullable().optional(),
|
|
661
|
-
coverageState: z5.string().nullable().optional(),
|
|
662
|
-
pageFetchState: z5.string().nullable().optional(),
|
|
663
|
-
robotsTxtState: z5.string().nullable().optional(),
|
|
664
|
-
crawlTime: z5.string().nullable().optional(),
|
|
665
|
-
lastCrawlResult: z5.string().nullable().optional(),
|
|
666
|
-
isMobileFriendly: z5.boolean().nullable().optional(),
|
|
667
|
-
richResults: z5.array(z5.string()).default([]),
|
|
668
|
-
inspectedAt: z5.string()
|
|
669
|
-
});
|
|
670
|
-
var indexTransitionSchema = z5.enum(["stable", "reindexed", "deindexed", "still-missing", "new"]);
|
|
671
|
-
var gscDeindexedRowSchema = z5.object({
|
|
672
|
-
url: z5.string(),
|
|
673
|
-
previousState: z5.string().nullable(),
|
|
674
|
-
currentState: z5.string().nullable(),
|
|
675
|
-
transitionDate: z5.string()
|
|
676
|
-
});
|
|
677
|
-
var gscReasonGroupSchema = z5.object({
|
|
678
|
-
reason: z5.string(),
|
|
679
|
-
count: z5.number(),
|
|
680
|
-
urls: z5.array(gscUrlInspectionDtoSchema).default([])
|
|
681
|
-
});
|
|
682
|
-
var gscCoverageSummaryDtoSchema = z5.object({
|
|
683
|
-
summary: z5.object({
|
|
684
|
-
total: z5.number(),
|
|
685
|
-
indexed: z5.number(),
|
|
686
|
-
notIndexed: z5.number(),
|
|
687
|
-
deindexed: z5.number(),
|
|
688
|
-
percentage: z5.number()
|
|
689
|
-
}),
|
|
690
|
-
lastInspectedAt: z5.string().nullable(),
|
|
691
|
-
indexed: z5.array(gscUrlInspectionDtoSchema).default([]),
|
|
692
|
-
notIndexed: z5.array(gscUrlInspectionDtoSchema).default([]),
|
|
693
|
-
deindexed: z5.array(gscDeindexedRowSchema).default([]),
|
|
694
|
-
reasonGroups: z5.array(gscReasonGroupSchema).default([])
|
|
695
|
-
});
|
|
696
|
-
var indexingNotificationDtoSchema = z5.object({
|
|
697
|
-
url: z5.string(),
|
|
698
|
-
type: z5.enum(["URL_UPDATED", "URL_DELETED"]),
|
|
699
|
-
notifiedAt: z5.string()
|
|
700
|
-
});
|
|
701
|
-
var indexingRequestResultDtoSchema = z5.object({
|
|
702
|
-
url: z5.string(),
|
|
703
|
-
type: z5.enum(["URL_UPDATED", "URL_DELETED"]),
|
|
704
|
-
notifiedAt: z5.string(),
|
|
705
|
-
status: z5.enum(["success", "error"]),
|
|
706
|
-
error: z5.string().optional()
|
|
707
|
-
});
|
|
708
|
-
var gscCoverageSnapshotDtoSchema = z5.object({
|
|
709
|
-
date: z5.string(),
|
|
710
|
-
indexed: z5.number(),
|
|
711
|
-
notIndexed: z5.number(),
|
|
712
|
-
reasonBreakdown: z5.record(z5.string(), z5.number()).default({})
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
// ../contracts/src/bing.ts
|
|
716
|
-
import { z as z6 } from "zod";
|
|
717
|
-
var bingConnectionDtoSchema = z6.object({
|
|
718
|
-
id: z6.string(),
|
|
719
|
-
domain: z6.string(),
|
|
720
|
-
siteUrl: z6.string().nullable().optional(),
|
|
721
|
-
createdAt: z6.string(),
|
|
722
|
-
updatedAt: z6.string()
|
|
723
|
-
});
|
|
724
|
-
var bingUrlInspectionDtoSchema = z6.object({
|
|
725
|
-
id: z6.string(),
|
|
726
|
-
url: z6.string(),
|
|
727
|
-
httpCode: z6.number().nullable().optional(),
|
|
728
|
-
inIndex: z6.boolean().nullable().optional(),
|
|
729
|
-
lastCrawledDate: z6.string().nullable().optional(),
|
|
730
|
-
inIndexDate: z6.string().nullable().optional(),
|
|
731
|
-
inspectedAt: z6.string(),
|
|
732
|
-
// Fields derived from GetUrlInfo response (more reliable than InIndex)
|
|
733
|
-
documentSize: z6.number().nullable().optional(),
|
|
734
|
-
anchorCount: z6.number().nullable().optional(),
|
|
735
|
-
discoveryDate: z6.string().nullable().optional()
|
|
736
|
-
});
|
|
737
|
-
var bingCoverageSummaryDtoSchema = z6.object({
|
|
738
|
-
summary: z6.object({
|
|
739
|
-
total: z6.number(),
|
|
740
|
-
indexed: z6.number(),
|
|
741
|
-
notIndexed: z6.number(),
|
|
742
|
-
unknown: z6.number().optional(),
|
|
743
|
-
percentage: z6.number()
|
|
744
|
-
}),
|
|
745
|
-
lastInspectedAt: z6.string().nullable(),
|
|
746
|
-
indexed: z6.array(bingUrlInspectionDtoSchema).default([]),
|
|
747
|
-
notIndexed: z6.array(bingUrlInspectionDtoSchema).default([]),
|
|
748
|
-
unknown: z6.array(bingUrlInspectionDtoSchema).default([]).optional()
|
|
749
|
-
});
|
|
750
|
-
var bingKeywordStatsDtoSchema = z6.object({
|
|
751
|
-
query: z6.string(),
|
|
752
|
-
impressions: z6.number(),
|
|
753
|
-
clicks: z6.number(),
|
|
754
|
-
ctr: z6.number(),
|
|
755
|
-
averagePosition: z6.number()
|
|
756
|
-
});
|
|
757
|
-
var bingCoverageSnapshotDtoSchema = z6.object({
|
|
758
|
-
date: z6.string(),
|
|
759
|
-
indexed: z6.number(),
|
|
760
|
-
notIndexed: z6.number(),
|
|
761
|
-
unknown: z6.number()
|
|
762
|
-
});
|
|
763
|
-
var bingSubmitResultDtoSchema = z6.object({
|
|
764
|
-
url: z6.string(),
|
|
765
|
-
status: z6.enum(["success", "error"]),
|
|
766
|
-
submittedAt: z6.string(),
|
|
767
|
-
error: z6.string().optional()
|
|
768
|
-
});
|
|
769
|
-
|
|
770
|
-
// ../contracts/src/wordpress.ts
|
|
771
|
-
import { z as z7 } from "zod";
|
|
772
|
-
var wordpressEnvSchema = z7.enum(["live", "staging"]);
|
|
773
|
-
var wordpressConnectionDtoSchema = z7.object({
|
|
774
|
-
projectName: z7.string(),
|
|
775
|
-
url: z7.string(),
|
|
776
|
-
stagingUrl: z7.string().optional(),
|
|
777
|
-
username: z7.string(),
|
|
778
|
-
defaultEnv: wordpressEnvSchema,
|
|
779
|
-
createdAt: z7.string(),
|
|
780
|
-
updatedAt: z7.string()
|
|
781
|
-
});
|
|
782
|
-
var wordpressSiteStatusDtoSchema = z7.object({
|
|
783
|
-
url: z7.string(),
|
|
784
|
-
reachable: z7.boolean(),
|
|
785
|
-
pageCount: z7.number().nullable().optional(),
|
|
786
|
-
version: z7.string().nullable().optional(),
|
|
787
|
-
error: z7.string().nullable().optional(),
|
|
788
|
-
plugins: z7.array(z7.string()).optional(),
|
|
789
|
-
authenticatedUser: z7.object({
|
|
790
|
-
id: z7.number(),
|
|
791
|
-
slug: z7.string()
|
|
792
|
-
}).nullable().optional()
|
|
793
|
-
});
|
|
794
|
-
var wordpressStatusDtoSchema = z7.object({
|
|
795
|
-
connected: z7.boolean(),
|
|
796
|
-
projectName: z7.string(),
|
|
797
|
-
defaultEnv: wordpressEnvSchema,
|
|
798
|
-
live: wordpressSiteStatusDtoSchema.nullable(),
|
|
799
|
-
staging: wordpressSiteStatusDtoSchema.nullable(),
|
|
800
|
-
adminUrl: z7.string().nullable().optional()
|
|
801
|
-
});
|
|
802
|
-
var wordpressPageSummaryDtoSchema = z7.object({
|
|
803
|
-
id: z7.number(),
|
|
804
|
-
slug: z7.string(),
|
|
805
|
-
title: z7.string(),
|
|
806
|
-
status: z7.string(),
|
|
807
|
-
modifiedAt: z7.string().nullable().optional(),
|
|
808
|
-
link: z7.string().nullable().optional()
|
|
809
|
-
});
|
|
810
|
-
var wordpressSeoStateDtoSchema = z7.object({
|
|
811
|
-
title: z7.string().nullable(),
|
|
812
|
-
description: z7.string().nullable(),
|
|
813
|
-
noindex: z7.boolean().nullable(),
|
|
814
|
-
writable: z7.boolean().default(false),
|
|
815
|
-
writeTargets: z7.array(z7.string()).default([])
|
|
816
|
-
});
|
|
817
|
-
var wordpressSchemaBlockDtoSchema = z7.object({
|
|
818
|
-
type: z7.string(),
|
|
819
|
-
json: z7.record(z7.string(), z7.unknown())
|
|
820
|
-
});
|
|
821
|
-
var wordpressPageDetailDtoSchema = wordpressPageSummaryDtoSchema.extend({
|
|
822
|
-
env: wordpressEnvSchema,
|
|
823
|
-
content: z7.string(),
|
|
824
|
-
seo: wordpressSeoStateDtoSchema,
|
|
825
|
-
schemaBlocks: z7.array(wordpressSchemaBlockDtoSchema).default([])
|
|
826
|
-
});
|
|
827
|
-
var wordpressDiffPageDtoSchema = wordpressPageDetailDtoSchema.extend({
|
|
828
|
-
contentHash: z7.string(),
|
|
829
|
-
contentSnippet: z7.string()
|
|
830
|
-
});
|
|
831
|
-
var wordpressManualAssistDtoSchema = z7.object({
|
|
832
|
-
manualRequired: z7.literal(true),
|
|
833
|
-
targetUrl: z7.string(),
|
|
834
|
-
adminUrl: z7.string().nullable().optional(),
|
|
835
|
-
content: z7.string(),
|
|
836
|
-
nextSteps: z7.array(z7.string()).default([])
|
|
837
|
-
});
|
|
838
|
-
var wordpressAuditIssueDtoSchema = z7.object({
|
|
839
|
-
slug: z7.string(),
|
|
840
|
-
severity: z7.enum(["high", "medium", "low"]),
|
|
841
|
-
code: z7.enum([
|
|
842
|
-
"noindex",
|
|
843
|
-
"missing-seo-title",
|
|
844
|
-
"missing-meta-description",
|
|
845
|
-
"missing-schema",
|
|
846
|
-
"thin-content"
|
|
847
|
-
]),
|
|
848
|
-
message: z7.string()
|
|
849
|
-
});
|
|
850
|
-
var wordpressAuditPageDtoSchema = z7.object({
|
|
851
|
-
slug: z7.string(),
|
|
852
|
-
title: z7.string(),
|
|
853
|
-
status: z7.string(),
|
|
854
|
-
wordCount: z7.number(),
|
|
855
|
-
seo: wordpressSeoStateDtoSchema,
|
|
856
|
-
schemaPresent: z7.boolean(),
|
|
857
|
-
issues: z7.array(wordpressAuditIssueDtoSchema).default([])
|
|
858
|
-
});
|
|
859
|
-
var wordpressBulkMetaEntryResultDtoSchema = z7.object({
|
|
860
|
-
slug: z7.string(),
|
|
861
|
-
status: z7.enum(["applied", "skipped", "manual"]),
|
|
862
|
-
error: z7.string().optional(),
|
|
863
|
-
manualAssist: wordpressManualAssistDtoSchema.optional()
|
|
864
|
-
});
|
|
865
|
-
var wordpressBulkMetaResultDtoSchema = z7.object({
|
|
866
|
-
env: wordpressEnvSchema,
|
|
867
|
-
strategy: z7.enum(["plugin", "manual"]),
|
|
868
|
-
results: z7.array(wordpressBulkMetaEntryResultDtoSchema)
|
|
869
|
-
});
|
|
870
|
-
var wordpressSchemaDeployEntryResultDtoSchema = z7.object({
|
|
871
|
-
slug: z7.string(),
|
|
872
|
-
status: z7.enum(["deployed", "stripped", "skipped", "failed"]),
|
|
873
|
-
schemasInjected: z7.array(z7.string()).optional(),
|
|
874
|
-
manualAssist: wordpressManualAssistDtoSchema.optional(),
|
|
875
|
-
error: z7.string().optional()
|
|
876
|
-
});
|
|
877
|
-
var wordpressSchemaDeployResultDtoSchema = z7.object({
|
|
878
|
-
env: wordpressEnvSchema,
|
|
879
|
-
results: z7.array(wordpressSchemaDeployEntryResultDtoSchema)
|
|
880
|
-
});
|
|
881
|
-
var wordpressSchemaStatusPageDtoSchema = z7.object({
|
|
882
|
-
slug: z7.string(),
|
|
883
|
-
title: z7.string(),
|
|
884
|
-
canonrySchemas: z7.array(z7.string()),
|
|
885
|
-
thirdPartySchemas: z7.array(z7.string()),
|
|
886
|
-
hasCanonrySchema: z7.boolean()
|
|
887
|
-
});
|
|
888
|
-
var wordpressSchemaStatusResultDtoSchema = z7.object({
|
|
889
|
-
env: wordpressEnvSchema,
|
|
890
|
-
pages: z7.array(wordpressSchemaStatusPageDtoSchema)
|
|
891
|
-
});
|
|
892
|
-
var wordpressOnboardStepDtoSchema = z7.object({
|
|
893
|
-
name: z7.string(),
|
|
894
|
-
status: z7.enum(["completed", "skipped", "failed"]),
|
|
895
|
-
summary: z7.string().optional(),
|
|
896
|
-
error: z7.string().optional()
|
|
897
|
-
});
|
|
898
|
-
var wordpressOnboardResultDtoSchema = z7.object({
|
|
899
|
-
projectName: z7.string(),
|
|
900
|
-
steps: z7.array(wordpressOnboardStepDtoSchema)
|
|
901
|
-
});
|
|
902
|
-
var wordpressDiffDtoSchema = z7.object({
|
|
903
|
-
slug: z7.string(),
|
|
904
|
-
live: wordpressDiffPageDtoSchema,
|
|
905
|
-
staging: wordpressDiffPageDtoSchema,
|
|
906
|
-
hasDifferences: z7.boolean(),
|
|
907
|
-
differences: z7.object({
|
|
908
|
-
title: z7.boolean(),
|
|
909
|
-
slug: z7.boolean(),
|
|
910
|
-
content: z7.boolean(),
|
|
911
|
-
seoTitle: z7.boolean(),
|
|
912
|
-
seoDescription: z7.boolean(),
|
|
913
|
-
noindex: z7.boolean(),
|
|
914
|
-
schema: z7.boolean()
|
|
915
|
-
})
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
// ../contracts/src/providers.ts
|
|
919
|
-
var ProviderIds = {
|
|
920
|
-
claude: "claude",
|
|
921
|
-
openai: "openai",
|
|
922
|
-
gemini: "gemini",
|
|
923
|
-
perplexity: "perplexity",
|
|
924
|
-
local: "local",
|
|
925
|
-
cdpChatgpt: "cdp:chatgpt",
|
|
926
|
-
zai: "zai"
|
|
927
|
-
};
|
|
928
|
-
var PROVIDER_IDS = Object.values(ProviderIds);
|
|
929
|
-
var SweepProviderIds = {
|
|
930
|
-
claude: ProviderIds.claude,
|
|
931
|
-
openai: ProviderIds.openai,
|
|
932
|
-
gemini: ProviderIds.gemini,
|
|
933
|
-
perplexity: ProviderIds.perplexity,
|
|
934
|
-
local: ProviderIds.local,
|
|
935
|
-
cdpChatgpt: ProviderIds.cdpChatgpt
|
|
936
|
-
};
|
|
937
|
-
var SWEEP_PROVIDER_IDS = Object.values(SweepProviderIds);
|
|
938
|
-
var AgentProviderIds = {
|
|
939
|
-
claude: ProviderIds.claude,
|
|
940
|
-
openai: ProviderIds.openai,
|
|
941
|
-
gemini: ProviderIds.gemini,
|
|
942
|
-
zai: ProviderIds.zai
|
|
943
|
-
};
|
|
944
|
-
var AGENT_PROVIDER_IDS = Object.values(AgentProviderIds);
|
|
945
|
-
function isAgentProviderId(value) {
|
|
946
|
-
return AGENT_PROVIDER_IDS.includes(value);
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
// ../contracts/src/run.ts
|
|
950
|
-
import { z as z8 } from "zod";
|
|
951
|
-
var runStatusSchema = z8.enum(["queued", "running", "completed", "partial", "failed", "cancelled"]);
|
|
952
|
-
var RunStatuses = runStatusSchema.enum;
|
|
953
|
-
var runKindSchema = z8.enum([
|
|
954
|
-
"answer-visibility",
|
|
955
|
-
"site-audit",
|
|
956
|
-
"gsc-sync",
|
|
957
|
-
"inspect-sitemap",
|
|
958
|
-
"ga-sync",
|
|
959
|
-
"bing-inspect",
|
|
960
|
-
"bing-inspect-sitemap",
|
|
961
|
-
"backlink-extract"
|
|
962
|
-
]);
|
|
963
|
-
var RunKinds = runKindSchema.enum;
|
|
964
|
-
var runTriggerSchema = z8.enum(["manual", "scheduled", "config-apply"]);
|
|
965
|
-
var RunTriggers = runTriggerSchema.enum;
|
|
966
|
-
var citationStateSchema = z8.enum(["cited", "not-cited"]);
|
|
967
|
-
var CitationStates = citationStateSchema.enum;
|
|
968
|
-
var visibilityStateSchema = z8.enum(["visible", "not-visible"]);
|
|
969
|
-
var VisibilityStates = visibilityStateSchema.enum;
|
|
970
|
-
var computedTransitionSchema = z8.enum(["new", "cited", "lost", "emerging", "not-cited"]);
|
|
971
|
-
var ComputedTransitions = computedTransitionSchema.enum;
|
|
972
|
-
var runDtoSchema = z8.object({
|
|
973
|
-
id: z8.string(),
|
|
974
|
-
projectId: z8.string(),
|
|
975
|
-
kind: runKindSchema,
|
|
976
|
-
status: runStatusSchema,
|
|
977
|
-
trigger: runTriggerSchema.default("manual"),
|
|
978
|
-
location: z8.string().nullable().optional(),
|
|
979
|
-
startedAt: z8.string().nullable().optional(),
|
|
980
|
-
finishedAt: z8.string().nullable().optional(),
|
|
981
|
-
error: z8.string().nullable().optional(),
|
|
982
|
-
createdAt: z8.string()
|
|
983
|
-
});
|
|
984
|
-
var groundingSourceSchema = z8.object({
|
|
985
|
-
uri: z8.string(),
|
|
986
|
-
title: z8.string()
|
|
987
|
-
});
|
|
988
|
-
var querySnapshotDtoSchema = z8.object({
|
|
989
|
-
id: z8.string(),
|
|
990
|
-
runId: z8.string(),
|
|
991
|
-
keywordId: z8.string(),
|
|
992
|
-
keyword: z8.string().optional(),
|
|
993
|
-
provider: providerNameSchema,
|
|
994
|
-
citationState: citationStateSchema,
|
|
995
|
-
answerMentioned: z8.boolean().optional(),
|
|
996
|
-
visibilityState: visibilityStateSchema.optional(),
|
|
997
|
-
transition: computedTransitionSchema.optional(),
|
|
998
|
-
answerText: z8.string().nullable().optional(),
|
|
999
|
-
citedDomains: z8.array(z8.string()).default([]),
|
|
1000
|
-
competitorOverlap: z8.array(z8.string()).default([]),
|
|
1001
|
-
recommendedCompetitors: z8.array(z8.string()).default([]),
|
|
1002
|
-
matchedTerms: z8.array(z8.string()).default([]),
|
|
1003
|
-
groundingSources: z8.array(groundingSourceSchema).default([]),
|
|
1004
|
-
searchQueries: z8.array(z8.string()).default([]),
|
|
1005
|
-
model: z8.string().nullable().optional(),
|
|
1006
|
-
location: z8.string().nullable().optional(),
|
|
1007
|
-
createdAt: z8.string()
|
|
1008
|
-
});
|
|
1009
|
-
var runDetailDtoSchema = runDtoSchema.extend({
|
|
1010
|
-
snapshots: z8.array(querySnapshotDtoSchema).optional()
|
|
1011
|
-
});
|
|
1012
|
-
var latestProjectRunDtoSchema = z8.object({
|
|
1013
|
-
totalRuns: z8.number().int().nonnegative(),
|
|
1014
|
-
run: runDetailDtoSchema.nullable()
|
|
1015
|
-
});
|
|
1016
|
-
var auditLogEntrySchema = z8.object({
|
|
1017
|
-
id: z8.string(),
|
|
1018
|
-
projectId: z8.string().nullable().optional(),
|
|
1019
|
-
actor: z8.string(),
|
|
1020
|
-
action: z8.string(),
|
|
1021
|
-
entityType: z8.string(),
|
|
1022
|
-
entityId: z8.string().nullable().optional(),
|
|
1023
|
-
diff: z8.unknown().optional(),
|
|
1024
|
-
createdAt: z8.string()
|
|
1025
|
-
});
|
|
1026
|
-
|
|
1027
|
-
// ../contracts/src/snapshot.ts
|
|
1028
|
-
import { z as z9 } from "zod";
|
|
1029
|
-
var snapshotAccuracySchema = z9.enum(["yes", "no", "unknown", "not-mentioned"]);
|
|
1030
|
-
var snapshotRequestSchema = z9.object({
|
|
1031
|
-
companyName: z9.string().min(1),
|
|
1032
|
-
domain: z9.string().min(1),
|
|
1033
|
-
phrases: z9.array(z9.string().min(1)).optional().default([]),
|
|
1034
|
-
competitors: z9.array(z9.string().min(1)).optional().default([])
|
|
1035
|
-
});
|
|
1036
|
-
var snapshotCompetitorEntrySchema = z9.object({
|
|
1037
|
-
name: z9.string(),
|
|
1038
|
-
count: z9.number().int().nonnegative()
|
|
1039
|
-
});
|
|
1040
|
-
var snapshotAuditFactorSchema = z9.object({
|
|
1041
|
-
id: z9.string(),
|
|
1042
|
-
name: z9.string(),
|
|
1043
|
-
weight: z9.number(),
|
|
1044
|
-
score: z9.number(),
|
|
1045
|
-
grade: z9.string(),
|
|
1046
|
-
status: z9.enum(["pass", "partial", "fail"]),
|
|
1047
|
-
findings: z9.array(z9.object({
|
|
1048
|
-
type: z9.string(),
|
|
1049
|
-
message: z9.string()
|
|
1050
|
-
})).default([]),
|
|
1051
|
-
recommendations: z9.array(z9.string()).default([])
|
|
1052
|
-
});
|
|
1053
|
-
var snapshotAuditSchema = z9.object({
|
|
1054
|
-
url: z9.string(),
|
|
1055
|
-
finalUrl: z9.string(),
|
|
1056
|
-
auditedAt: z9.string(),
|
|
1057
|
-
overallScore: z9.number(),
|
|
1058
|
-
overallGrade: z9.string(),
|
|
1059
|
-
summary: z9.string(),
|
|
1060
|
-
factors: z9.array(snapshotAuditFactorSchema).default([])
|
|
1061
|
-
});
|
|
1062
|
-
var snapshotProfileSchema = z9.object({
|
|
1063
|
-
industry: z9.string(),
|
|
1064
|
-
summary: z9.string(),
|
|
1065
|
-
services: z9.array(z9.string()).default([]),
|
|
1066
|
-
categoryTerms: z9.array(z9.string()).default([])
|
|
1067
|
-
});
|
|
1068
|
-
var snapshotProviderResultSchema = z9.object({
|
|
1069
|
-
provider: z9.string(),
|
|
1070
|
-
displayName: z9.string(),
|
|
1071
|
-
model: z9.string().nullable().optional(),
|
|
1072
|
-
mentioned: z9.boolean(),
|
|
1073
|
-
cited: z9.boolean(),
|
|
1074
|
-
describedAccurately: snapshotAccuracySchema,
|
|
1075
|
-
accuracyNotes: z9.string().nullable().optional(),
|
|
1076
|
-
incorrectClaims: z9.array(z9.string()).default([]),
|
|
1077
|
-
recommendedCompetitors: z9.array(z9.string()).default([]),
|
|
1078
|
-
citedDomains: z9.array(z9.string()).default([]),
|
|
1079
|
-
groundingSources: z9.array(groundingSourceSchema).default([]),
|
|
1080
|
-
searchQueries: z9.array(z9.string()).default([]),
|
|
1081
|
-
answerText: z9.string(),
|
|
1082
|
-
error: z9.string().nullable().optional()
|
|
1083
|
-
});
|
|
1084
|
-
var snapshotQueryResultSchema = z9.object({
|
|
1085
|
-
phrase: z9.string(),
|
|
1086
|
-
providerResults: z9.array(snapshotProviderResultSchema).default([])
|
|
1087
|
-
});
|
|
1088
|
-
var snapshotSummarySchema = z9.object({
|
|
1089
|
-
totalQueries: z9.number().int().nonnegative(),
|
|
1090
|
-
totalProviders: z9.number().int().nonnegative(),
|
|
1091
|
-
totalComparisons: z9.number().int().nonnegative(),
|
|
1092
|
-
mentionCount: z9.number().int().nonnegative(),
|
|
1093
|
-
citationCount: z9.number().int().nonnegative(),
|
|
1094
|
-
topCompetitors: z9.array(snapshotCompetitorEntrySchema).default([]),
|
|
1095
|
-
visibilityGap: z9.string(),
|
|
1096
|
-
whatThisMeans: z9.array(z9.string()).default([]),
|
|
1097
|
-
recommendedActions: z9.array(z9.string()).default([])
|
|
1098
|
-
});
|
|
1099
|
-
var snapshotReportSchema = z9.object({
|
|
1100
|
-
companyName: z9.string(),
|
|
1101
|
-
domain: z9.string(),
|
|
1102
|
-
homepageUrl: z9.string(),
|
|
1103
|
-
generatedAt: z9.string(),
|
|
1104
|
-
phrases: z9.array(z9.string()).default([]),
|
|
1105
|
-
competitors: z9.array(z9.string()).default([]),
|
|
1106
|
-
profile: snapshotProfileSchema,
|
|
1107
|
-
audit: snapshotAuditSchema,
|
|
1108
|
-
queryResults: z9.array(snapshotQueryResultSchema).default([]),
|
|
1109
|
-
summary: snapshotSummarySchema
|
|
1110
|
-
});
|
|
1111
|
-
|
|
1112
|
-
// ../contracts/src/schedule.ts
|
|
1113
|
-
import { z as z10 } from "zod";
|
|
1114
|
-
var scheduleDtoSchema = z10.object({
|
|
1115
|
-
id: z10.string(),
|
|
1116
|
-
projectId: z10.string(),
|
|
1117
|
-
cronExpr: z10.string(),
|
|
1118
|
-
preset: z10.string().nullable().optional(),
|
|
1119
|
-
timezone: z10.string().default("UTC"),
|
|
1120
|
-
enabled: z10.boolean().default(true),
|
|
1121
|
-
providers: z10.array(providerNameSchema).default([]),
|
|
1122
|
-
lastRunAt: z10.string().nullable().optional(),
|
|
1123
|
-
nextRunAt: z10.string().nullable().optional(),
|
|
1124
|
-
createdAt: z10.string(),
|
|
1125
|
-
updatedAt: z10.string()
|
|
1126
|
-
});
|
|
1127
|
-
var scheduleUpsertRequestSchema = z10.object({
|
|
1128
|
-
preset: z10.string().optional(),
|
|
1129
|
-
cron: z10.string().optional(),
|
|
1130
|
-
timezone: z10.string().optional().default("UTC"),
|
|
1131
|
-
enabled: z10.boolean().optional().default(true),
|
|
1132
|
-
providers: z10.array(providerNameSchema).optional().default([])
|
|
1133
|
-
}).refine(
|
|
1134
|
-
(data) => data.preset && !data.cron || !data.preset && data.cron,
|
|
1135
|
-
{ message: 'Exactly one of "preset" or "cron" must be provided' }
|
|
1136
|
-
);
|
|
1137
|
-
|
|
1138
|
-
// ../contracts/src/analytics.ts
|
|
1139
|
-
import { z as z11 } from "zod";
|
|
1140
|
-
var visibilityMetricModeSchema = z11.enum(["answer", "citation"]);
|
|
1141
|
-
var VisibilityMetricModes = visibilityMetricModeSchema.enum;
|
|
1142
|
-
function parseWindow(value) {
|
|
1143
|
-
if (value === "7d" || value === "30d" || value === "90d" || value === "all") return value;
|
|
1144
|
-
return "all";
|
|
1145
|
-
}
|
|
1146
|
-
function windowCutoff(window) {
|
|
1147
|
-
if (window === "all") return null;
|
|
1148
|
-
const days = window === "7d" ? 7 : window === "30d" ? 30 : 90;
|
|
1149
|
-
const d = /* @__PURE__ */ new Date();
|
|
1150
|
-
d.setDate(d.getDate() - days);
|
|
1151
|
-
return d.toISOString();
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
// ../contracts/src/source-categories.ts
|
|
1155
|
-
var SOURCE_CATEGORY_RULES = [
|
|
1156
|
-
// Forums
|
|
1157
|
-
{ pattern: "reddit.com", category: "forum", label: "Reddit" },
|
|
1158
|
-
{ pattern: "quora.com", category: "forum", label: "Quora" },
|
|
1159
|
-
{ pattern: "stackexchange.com", category: "forum", label: "Stack Exchange" },
|
|
1160
|
-
{ pattern: "stackoverflow.com", category: "forum", label: "Stack Overflow" },
|
|
1161
|
-
{ pattern: "discourse.org", category: "forum", label: "Discourse" },
|
|
1162
|
-
// Social
|
|
1163
|
-
{ pattern: "linkedin.com", category: "social", label: "LinkedIn" },
|
|
1164
|
-
{ pattern: "twitter.com", category: "social", label: "X (Twitter)" },
|
|
1165
|
-
{ pattern: "x.com", category: "social", label: "X (Twitter)" },
|
|
1166
|
-
{ pattern: "facebook.com", category: "social", label: "Facebook" },
|
|
1167
|
-
{ pattern: "instagram.com", category: "social", label: "Instagram" },
|
|
1168
|
-
{ pattern: "threads.net", category: "social", label: "Threads" },
|
|
1169
|
-
{ pattern: "pinterest.com", category: "social", label: "Pinterest" },
|
|
1170
|
-
{ pattern: "tiktok.com", category: "social", label: "TikTok" },
|
|
1171
|
-
// Video
|
|
1172
|
-
{ pattern: "youtube.com", category: "video", label: "YouTube" },
|
|
1173
|
-
{ pattern: "youtu.be", category: "video", label: "YouTube" },
|
|
1174
|
-
{ pattern: "vimeo.com", category: "video", label: "Vimeo" },
|
|
1175
|
-
// News
|
|
1176
|
-
{ pattern: "nytimes.com", category: "news", label: "NY Times" },
|
|
1177
|
-
{ pattern: "bbc.com", category: "news", label: "BBC" },
|
|
1178
|
-
{ pattern: "bbc.co.uk", category: "news", label: "BBC" },
|
|
1179
|
-
{ pattern: "cnn.com", category: "news", label: "CNN" },
|
|
1180
|
-
{ pattern: "reuters.com", category: "news", label: "Reuters" },
|
|
1181
|
-
{ pattern: "apnews.com", category: "news", label: "AP News" },
|
|
1182
|
-
{ pattern: "theguardian.com", category: "news", label: "The Guardian" },
|
|
1183
|
-
{ pattern: "washingtonpost.com", category: "news", label: "Washington Post" },
|
|
1184
|
-
{ pattern: "wsj.com", category: "news", label: "WSJ" },
|
|
1185
|
-
{ pattern: "forbes.com", category: "news", label: "Forbes" },
|
|
1186
|
-
{ pattern: "techcrunch.com", category: "news", label: "TechCrunch" },
|
|
1187
|
-
{ pattern: "theverge.com", category: "news", label: "The Verge" },
|
|
1188
|
-
{ pattern: "wired.com", category: "news", label: "Wired" },
|
|
1189
|
-
{ pattern: "arstechnica.com", category: "news", label: "Ars Technica" },
|
|
1190
|
-
// Reference
|
|
1191
|
-
{ pattern: "wikipedia.org", category: "reference", label: "Wikipedia" },
|
|
1192
|
-
{ pattern: "wikimedia.org", category: "reference", label: "Wikimedia" },
|
|
1193
|
-
{ pattern: "britannica.com", category: "reference", label: "Britannica" },
|
|
1194
|
-
{ pattern: "merriam-webster.com", category: "reference", label: "Merriam-Webster" },
|
|
1195
|
-
// Blog / Content platforms
|
|
1196
|
-
{ pattern: "medium.com", category: "blog", label: "Medium" },
|
|
1197
|
-
{ pattern: "substack.com", category: "blog", label: "Substack" },
|
|
1198
|
-
{ pattern: "dev.to", category: "blog", label: "DEV Community" },
|
|
1199
|
-
{ pattern: "hashnode.dev", category: "blog", label: "Hashnode" },
|
|
1200
|
-
{ pattern: "wordpress.com", category: "blog", label: "WordPress" },
|
|
1201
|
-
{ pattern: "blogger.com", category: "blog", label: "Blogger" },
|
|
1202
|
-
{ pattern: "hubspot.com", category: "blog", label: "HubSpot" },
|
|
1203
|
-
// E-commerce
|
|
1204
|
-
{ pattern: "amazon.com", category: "ecommerce", label: "Amazon" },
|
|
1205
|
-
{ pattern: "amazon.co.uk", category: "ecommerce", label: "Amazon UK" },
|
|
1206
|
-
{ pattern: "shopify.com", category: "ecommerce", label: "Shopify" },
|
|
1207
|
-
{ pattern: "ebay.com", category: "ecommerce", label: "eBay" },
|
|
1208
|
-
// Academic
|
|
1209
|
-
{ pattern: "scholar.google.com", category: "academic", label: "Google Scholar" },
|
|
1210
|
-
{ pattern: "arxiv.org", category: "academic", label: "arXiv" },
|
|
1211
|
-
{ pattern: "pubmed.ncbi.nlm.nih.gov", category: "academic", label: "PubMed" },
|
|
1212
|
-
{ pattern: "researchgate.net", category: "academic", label: "ResearchGate" },
|
|
1213
|
-
{ pattern: ".edu", category: "academic", label: "Academic (.edu)" }
|
|
1214
|
-
];
|
|
1215
|
-
var CATEGORY_LABELS = {
|
|
1216
|
-
social: "Social Media",
|
|
1217
|
-
forum: "Forums & Q&A",
|
|
1218
|
-
news: "News & Media",
|
|
1219
|
-
reference: "Reference",
|
|
1220
|
-
blog: "Blogs & Content",
|
|
1221
|
-
ecommerce: "E-commerce",
|
|
1222
|
-
video: "Video",
|
|
1223
|
-
academic: "Academic",
|
|
1224
|
-
other: "Other"
|
|
1225
|
-
};
|
|
1226
|
-
function categorizeSource(uri) {
|
|
1227
|
-
let domain;
|
|
1228
|
-
try {
|
|
1229
|
-
const url = new URL(uri.startsWith("http") ? uri : `https://${uri}`);
|
|
1230
|
-
domain = url.hostname.replace(/^www\./, "");
|
|
1231
|
-
} catch {
|
|
1232
|
-
domain = uri.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? uri;
|
|
1233
|
-
}
|
|
1234
|
-
const domainLower = domain.toLowerCase();
|
|
1235
|
-
for (const rule of SOURCE_CATEGORY_RULES) {
|
|
1236
|
-
if (domainLower === rule.pattern || domainLower.endsWith(`.${rule.pattern}`) || rule.pattern.startsWith(".") && domainLower.endsWith(rule.pattern)) {
|
|
1237
|
-
return { category: rule.category, label: rule.label, domain };
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
return { category: "other", label: CATEGORY_LABELS.other, domain };
|
|
1241
|
-
}
|
|
1242
|
-
function categoryLabel(category) {
|
|
1243
|
-
return CATEGORY_LABELS[category];
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
// ../contracts/src/ga.ts
|
|
1247
|
-
import { z as z12 } from "zod";
|
|
1248
|
-
var ga4ConnectionDtoSchema = z12.object({
|
|
1249
|
-
id: z12.string(),
|
|
1250
|
-
projectId: z12.string(),
|
|
1251
|
-
propertyId: z12.string(),
|
|
1252
|
-
clientEmail: z12.string(),
|
|
1253
|
-
connected: z12.boolean(),
|
|
1254
|
-
createdAt: z12.string(),
|
|
1255
|
-
updatedAt: z12.string()
|
|
1256
|
-
});
|
|
1257
|
-
var ga4TrafficSnapshotDtoSchema = z12.object({
|
|
1258
|
-
date: z12.string(),
|
|
1259
|
-
landingPage: z12.string(),
|
|
1260
|
-
sessions: z12.number(),
|
|
1261
|
-
organicSessions: z12.number(),
|
|
1262
|
-
users: z12.number()
|
|
1263
|
-
});
|
|
1264
|
-
var ga4SourceDimensionSchema = z12.enum(["session", "first_user", "manual_utm"]);
|
|
1265
|
-
var ga4AiReferralDtoSchema = z12.object({
|
|
1266
|
-
source: z12.string(),
|
|
1267
|
-
medium: z12.string(),
|
|
1268
|
-
sessions: z12.number(),
|
|
1269
|
-
users: z12.number(),
|
|
1270
|
-
sourceDimension: ga4SourceDimensionSchema
|
|
1271
|
-
});
|
|
1272
|
-
var ga4SocialReferralDtoSchema = z12.object({
|
|
1273
|
-
source: z12.string(),
|
|
1274
|
-
medium: z12.string(),
|
|
1275
|
-
sessions: z12.number(),
|
|
1276
|
-
users: z12.number(),
|
|
1277
|
-
/** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
|
|
1278
|
-
channelGroup: z12.string()
|
|
1279
|
-
});
|
|
1280
|
-
var ga4TrafficSummaryDtoSchema = z12.object({
|
|
1281
|
-
totalSessions: z12.number(),
|
|
1282
|
-
totalOrganicSessions: z12.number(),
|
|
1283
|
-
totalUsers: z12.number(),
|
|
1284
|
-
topPages: z12.array(z12.object({
|
|
1285
|
-
landingPage: z12.string(),
|
|
1286
|
-
sessions: z12.number(),
|
|
1287
|
-
organicSessions: z12.number(),
|
|
1288
|
-
users: z12.number()
|
|
1289
|
-
})),
|
|
1290
|
-
aiReferrals: z12.array(ga4AiReferralDtoSchema),
|
|
1291
|
-
/** Deduped AI session total: MAX(sessions) per date+source+medium across attribution dimensions, then summed. */
|
|
1292
|
-
aiSessionsDeduped: z12.number(),
|
|
1293
|
-
/** Deduped AI user total: MAX(users) per date+source+medium across attribution dimensions, then summed. */
|
|
1294
|
-
aiUsersDeduped: z12.number(),
|
|
1295
|
-
socialReferrals: z12.array(ga4SocialReferralDtoSchema),
|
|
1296
|
-
/** Total social sessions (session-scoped, no cross-dimension dedup needed). */
|
|
1297
|
-
socialSessions: z12.number(),
|
|
1298
|
-
/** Total social users (session-scoped, no cross-dimension dedup needed). */
|
|
1299
|
-
socialUsers: z12.number(),
|
|
1300
|
-
/** Organic sessions as a percentage of total sessions (0–100, rounded). */
|
|
1301
|
-
organicSharePct: z12.number(),
|
|
1302
|
-
/** Deduped AI sessions as a percentage of total sessions (0–100, rounded). */
|
|
1303
|
-
aiSharePct: z12.number(),
|
|
1304
|
-
/** Social sessions as a percentage of total sessions (0–100, rounded). */
|
|
1305
|
-
socialSharePct: z12.number(),
|
|
1306
|
-
lastSyncedAt: z12.string().nullable()
|
|
1307
|
-
});
|
|
1308
|
-
var ga4AiReferralHistoryEntrySchema = z12.object({
|
|
1309
|
-
date: z12.string(),
|
|
1310
|
-
source: z12.string(),
|
|
1311
|
-
medium: z12.string(),
|
|
1312
|
-
sessions: z12.number(),
|
|
1313
|
-
users: z12.number(),
|
|
1314
|
-
/** Which GA4 dimension this row came from: session (sessionSource), first_user (firstUserSource), or manual_utm (utm_source parameter) */
|
|
1315
|
-
sourceDimension: ga4SourceDimensionSchema
|
|
1316
|
-
});
|
|
1317
|
-
var ga4SocialReferralHistoryEntrySchema = z12.object({
|
|
1318
|
-
date: z12.string(),
|
|
1319
|
-
source: z12.string(),
|
|
1320
|
-
medium: z12.string(),
|
|
1321
|
-
sessions: z12.number(),
|
|
1322
|
-
users: z12.number(),
|
|
1323
|
-
/** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
|
|
1324
|
-
channelGroup: z12.string()
|
|
1325
|
-
});
|
|
1326
|
-
var ga4SessionHistoryEntrySchema = z12.object({
|
|
1327
|
-
date: z12.string(),
|
|
1328
|
-
sessions: z12.number(),
|
|
1329
|
-
organicSessions: z12.number(),
|
|
1330
|
-
users: z12.number()
|
|
1331
|
-
});
|
|
1332
|
-
|
|
1333
|
-
// ../contracts/src/answer-visibility.ts
|
|
1334
|
-
var GENERIC_TOKENS = /* @__PURE__ */ new Set([
|
|
1335
|
-
"agency",
|
|
1336
|
-
"app",
|
|
1337
|
-
"company",
|
|
1338
|
-
"corp",
|
|
1339
|
-
"group",
|
|
1340
|
-
"health",
|
|
1341
|
-
"inc",
|
|
1342
|
-
"llc",
|
|
1343
|
-
"online",
|
|
1344
|
-
"platform",
|
|
1345
|
-
"services",
|
|
1346
|
-
"site",
|
|
1347
|
-
"solutions",
|
|
1348
|
-
"software",
|
|
1349
|
-
"systems",
|
|
1350
|
-
"tech"
|
|
1351
|
-
]);
|
|
1352
|
-
function extractAnswerMentions(answerText, displayName, domains) {
|
|
1353
|
-
if (!answerText) return { mentioned: false, matchedTerms: [] };
|
|
1354
|
-
const matchedTerms = [];
|
|
1355
|
-
const lowerAnswer = answerText.toLowerCase();
|
|
1356
|
-
for (const domain of domains) {
|
|
1357
|
-
const normalizedDomain = normalizeProjectDomain(domain);
|
|
1358
|
-
if (!normalizedDomain || !normalizedDomain.includes(".")) continue;
|
|
1359
|
-
if (domainMentioned(lowerAnswer, normalizedDomain)) {
|
|
1360
|
-
matchedTerms.push(normalizedDomain);
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
const normalizedDisplayName = normalizeText(displayName);
|
|
1364
|
-
if (normalizedDisplayName && normalizeText(answerText).includes(normalizedDisplayName)) {
|
|
1365
|
-
matchedTerms.push(displayName);
|
|
1366
|
-
}
|
|
1367
|
-
const tokens = collectDistinctiveTokens(displayName, domains);
|
|
1368
|
-
let tokenMatches = 0;
|
|
1369
|
-
const matchedTokens = [];
|
|
1370
|
-
for (const token of tokens) {
|
|
1371
|
-
if (new RegExp(`\\b${escapeRegExp(token)}\\b`).test(lowerAnswer)) {
|
|
1372
|
-
tokenMatches++;
|
|
1373
|
-
matchedTokens.push(token);
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
const tokenThresholdMet = tokens.length > 0 && (tokens.length === 1 && tokenMatches >= 1 || tokenMatches >= Math.min(2, tokens.length));
|
|
1377
|
-
if (tokenThresholdMet) {
|
|
1378
|
-
matchedTerms.push(...matchedTokens);
|
|
1379
|
-
}
|
|
1380
|
-
const unique = [...new Set(matchedTerms)];
|
|
1381
|
-
const domainMatches3 = unique.filter((t) => t.includes("."));
|
|
1382
|
-
const dedupedFinal = unique.filter((term) => {
|
|
1383
|
-
if (term.includes(".")) return true;
|
|
1384
|
-
return !domainMatches3.some((d) => d.toLowerCase().startsWith(term.toLowerCase() + "."));
|
|
1385
|
-
});
|
|
1386
|
-
return { mentioned: dedupedFinal.length > 0, matchedTerms: dedupedFinal };
|
|
1387
|
-
}
|
|
1388
|
-
function determineAnswerMentioned(answerText, displayName, domains) {
|
|
1389
|
-
return extractAnswerMentions(answerText, displayName, domains).mentioned;
|
|
1390
|
-
}
|
|
1391
|
-
function visibilityStateFromAnswerMentioned(answerMentioned) {
|
|
1392
|
-
return answerMentioned ? "visible" : "not-visible";
|
|
1393
|
-
}
|
|
1394
|
-
function brandKeyFromText(value) {
|
|
1395
|
-
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1396
|
-
}
|
|
1397
|
-
function domainMentioned(lowerAnswer, normalizedDomain) {
|
|
1398
|
-
const escapedDomain = escapeRegExp(normalizedDomain.toLowerCase());
|
|
1399
|
-
const patterns = [
|
|
1400
|
-
new RegExp(`(^|[^a-z0-9-])${escapedDomain}($|[^a-z0-9-])`),
|
|
1401
|
-
new RegExp(`https?://(?:www\\.)?${escapedDomain}(?:[/:?#]|$)`),
|
|
1402
|
-
new RegExp(`www\\.${escapedDomain}(?:[/:?#]|$)`)
|
|
1403
|
-
];
|
|
1404
|
-
return patterns.some((pattern) => pattern.test(lowerAnswer));
|
|
1405
|
-
}
|
|
1406
|
-
function collectDistinctiveTokens(displayName, domains) {
|
|
1407
|
-
const tokens = /* @__PURE__ */ new Set();
|
|
1408
|
-
for (const token of extractDistinctiveTokens(displayName)) {
|
|
1409
|
-
tokens.add(token);
|
|
1410
|
-
}
|
|
1411
|
-
for (const domain of domains) {
|
|
1412
|
-
const hostname = normalizeProjectDomain(domain).split("/")[0] ?? "";
|
|
1413
|
-
for (const label of hostname.split(".").filter(Boolean)) {
|
|
1414
|
-
const token = label.replace(/[^a-z0-9]/gi, "").toLowerCase();
|
|
1415
|
-
if (isDistinctiveToken(token)) tokens.add(token);
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
return [...tokens];
|
|
1419
|
-
}
|
|
1420
|
-
function extractDistinctiveTokens(value) {
|
|
1421
|
-
return normalizeText(value).split(" ").filter(isDistinctiveToken);
|
|
1422
|
-
}
|
|
1423
|
-
function isDistinctiveToken(token) {
|
|
1424
|
-
if (token.length < 4) return false;
|
|
1425
|
-
return !GENERIC_TOKENS.has(token);
|
|
1426
|
-
}
|
|
1427
|
-
function normalizeText(value) {
|
|
1428
|
-
return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
1429
|
-
}
|
|
1430
|
-
function escapeRegExp(value) {
|
|
1431
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
// ../contracts/src/agent.ts
|
|
1435
|
-
import { z as z13 } from "zod";
|
|
1436
|
-
var memorySourceSchema = z13.enum(["aero", "user", "compaction"]);
|
|
1437
|
-
var MemorySources = memorySourceSchema.enum;
|
|
1438
|
-
var AGENT_MEMORY_VALUE_MAX_BYTES = 2 * 1024;
|
|
1439
|
-
var AGENT_MEMORY_KEY_MAX_LENGTH = 128;
|
|
1440
|
-
var agentMemoryUpsertRequestSchema = z13.object({
|
|
1441
|
-
key: z13.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH),
|
|
1442
|
-
value: z13.string().min(1)
|
|
1443
|
-
});
|
|
1444
|
-
var agentMemoryDeleteRequestSchema = z13.object({
|
|
1445
|
-
key: z13.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH)
|
|
1446
|
-
});
|
|
1447
|
-
|
|
1448
|
-
// ../contracts/src/backlinks.ts
|
|
1449
|
-
import { z as z14 } from "zod";
|
|
1450
|
-
var ccReleaseSyncStatusSchema = z14.enum(["queued", "downloading", "querying", "ready", "failed"]);
|
|
1451
|
-
var CcReleaseSyncStatuses = ccReleaseSyncStatusSchema.enum;
|
|
1452
|
-
var ccReleaseSyncDtoSchema = z14.object({
|
|
1453
|
-
id: z14.string(),
|
|
1454
|
-
release: z14.string(),
|
|
1455
|
-
status: ccReleaseSyncStatusSchema,
|
|
1456
|
-
phaseDetail: z14.string().nullable().optional(),
|
|
1457
|
-
vertexPath: z14.string().nullable().optional(),
|
|
1458
|
-
edgesPath: z14.string().nullable().optional(),
|
|
1459
|
-
vertexSha256: z14.string().nullable().optional(),
|
|
1460
|
-
edgesSha256: z14.string().nullable().optional(),
|
|
1461
|
-
vertexBytes: z14.number().int().nullable().optional(),
|
|
1462
|
-
edgesBytes: z14.number().int().nullable().optional(),
|
|
1463
|
-
projectsProcessed: z14.number().int().nullable().optional(),
|
|
1464
|
-
domainsDiscovered: z14.number().int().nullable().optional(),
|
|
1465
|
-
downloadStartedAt: z14.string().nullable().optional(),
|
|
1466
|
-
downloadFinishedAt: z14.string().nullable().optional(),
|
|
1467
|
-
queryStartedAt: z14.string().nullable().optional(),
|
|
1468
|
-
queryFinishedAt: z14.string().nullable().optional(),
|
|
1469
|
-
error: z14.string().nullable().optional(),
|
|
1470
|
-
createdAt: z14.string(),
|
|
1471
|
-
updatedAt: z14.string()
|
|
1472
|
-
});
|
|
1473
|
-
var backlinkDomainDtoSchema = z14.object({
|
|
1474
|
-
linkingDomain: z14.string(),
|
|
1475
|
-
numHosts: z14.number().int()
|
|
1476
|
-
});
|
|
1477
|
-
var backlinkSummaryDtoSchema = z14.object({
|
|
1478
|
-
projectId: z14.string(),
|
|
1479
|
-
release: z14.string(),
|
|
1480
|
-
targetDomain: z14.string(),
|
|
1481
|
-
totalLinkingDomains: z14.number().int(),
|
|
1482
|
-
totalHosts: z14.number().int(),
|
|
1483
|
-
top10HostsShare: z14.string(),
|
|
1484
|
-
queriedAt: z14.string()
|
|
1485
|
-
});
|
|
1486
|
-
var backlinkListResponseSchema = z14.object({
|
|
1487
|
-
summary: backlinkSummaryDtoSchema.nullable(),
|
|
1488
|
-
total: z14.number().int(),
|
|
1489
|
-
rows: z14.array(backlinkDomainDtoSchema)
|
|
1490
|
-
});
|
|
1491
|
-
var backlinkHistoryEntrySchema = z14.object({
|
|
1492
|
-
release: z14.string(),
|
|
1493
|
-
totalLinkingDomains: z14.number().int(),
|
|
1494
|
-
totalHosts: z14.number().int(),
|
|
1495
|
-
top10HostsShare: z14.string(),
|
|
1496
|
-
queriedAt: z14.string()
|
|
1497
|
-
});
|
|
1498
|
-
var backlinksInstallStatusDtoSchema = z14.object({
|
|
1499
|
-
duckdbInstalled: z14.boolean(),
|
|
1500
|
-
duckdbVersion: z14.string().nullable().optional(),
|
|
1501
|
-
duckdbSpec: z14.string(),
|
|
1502
|
-
pluginDir: z14.string()
|
|
1503
|
-
});
|
|
1504
|
-
var backlinksInstallResultDtoSchema = z14.object({
|
|
1505
|
-
installed: z14.boolean(),
|
|
1506
|
-
version: z14.string(),
|
|
1507
|
-
path: z14.string(),
|
|
1508
|
-
alreadyPresent: z14.boolean()
|
|
1509
|
-
});
|
|
1510
|
-
var ccAvailableReleaseSchema = z14.object({
|
|
1511
|
-
release: z14.string(),
|
|
1512
|
-
vertexUrl: z14.string(),
|
|
1513
|
-
edgesUrl: z14.string(),
|
|
1514
|
-
vertexBytes: z14.number().int().nullable(),
|
|
1515
|
-
edgesBytes: z14.number().int().nullable(),
|
|
1516
|
-
lastModified: z14.string().nullable()
|
|
1517
|
-
});
|
|
1518
|
-
var ccCachedReleaseSchema = z14.object({
|
|
1519
|
-
release: z14.string(),
|
|
1520
|
-
syncStatus: ccReleaseSyncStatusSchema.nullable(),
|
|
1521
|
-
bytes: z14.number().int(),
|
|
1522
|
-
lastUsedAt: z14.string().nullable()
|
|
1523
|
-
});
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: { "Content-Type": "application/json" },
|
|
153
|
+
body: JSON.stringify(payload),
|
|
154
|
+
signal: controller.signal
|
|
155
|
+
}).catch(() => {
|
|
156
|
+
}).finally(() => clearTimeout(timeout));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/server.ts
|
|
160
|
+
import { createRequire as createRequire3 } from "module";
|
|
161
|
+
import crypto28 from "crypto";
|
|
162
|
+
import fs12 from "fs";
|
|
163
|
+
import path14 from "path";
|
|
164
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
165
|
+
import { eq as eq30 } from "drizzle-orm";
|
|
166
|
+
import Fastify from "fastify";
|
|
1524
167
|
|
|
1525
168
|
// ../api-routes/src/auth.ts
|
|
1526
169
|
import crypto2 from "crypto";
|
|
@@ -2132,11 +775,11 @@ function queueRunIfProjectIdle(db, params) {
|
|
|
2132
775
|
async function runRoutes(app, opts) {
|
|
2133
776
|
app.post("/projects/:name/runs", async (request, reply) => {
|
|
2134
777
|
const project = resolveProject(app.db, request.params.name);
|
|
2135
|
-
const
|
|
2136
|
-
if (kind !== "answer-visibility") throw unsupportedKind(kind);
|
|
778
|
+
const body = parseRunTriggerRequest(request.body ?? {});
|
|
2137
779
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2138
|
-
const
|
|
2139
|
-
const
|
|
780
|
+
const kind = body.kind ?? RunKinds["answer-visibility"];
|
|
781
|
+
const trigger = body.trigger ?? RunTriggers.manual;
|
|
782
|
+
const rawProviders = body.providers;
|
|
2140
783
|
if (rawProviders?.length) {
|
|
2141
784
|
const normalized = rawProviders.map((p) => p.trim().toLowerCase()).filter(Boolean);
|
|
2142
785
|
const validNames = opts.validProviderNames ?? [];
|
|
@@ -2154,13 +797,13 @@ async function runRoutes(app, opts) {
|
|
|
2154
797
|
const providers = rawProviders?.length ? rawProviders : void 0;
|
|
2155
798
|
let resolvedLocation;
|
|
2156
799
|
const projectLocations = parseJsonColumn(project.locations, []);
|
|
2157
|
-
if (
|
|
800
|
+
if (body.noLocation) {
|
|
2158
801
|
resolvedLocation = null;
|
|
2159
|
-
} else if (
|
|
2160
|
-
} else if (
|
|
2161
|
-
const loc = projectLocations.find((l) => l.label ===
|
|
802
|
+
} else if (body.allLocations) {
|
|
803
|
+
} else if (body.location) {
|
|
804
|
+
const loc = projectLocations.find((l) => l.label === body.location);
|
|
2162
805
|
if (!loc) {
|
|
2163
|
-
throw validationError(`Location "${
|
|
806
|
+
throw validationError(`Location "${body.location}" not found. Configure it first.`);
|
|
2164
807
|
}
|
|
2165
808
|
resolvedLocation = loc;
|
|
2166
809
|
} else if (project.defaultLocation) {
|
|
@@ -2170,7 +813,7 @@ async function runRoutes(app, opts) {
|
|
|
2170
813
|
}
|
|
2171
814
|
resolvedLocation = loc;
|
|
2172
815
|
}
|
|
2173
|
-
if (
|
|
816
|
+
if (body.allLocations) {
|
|
2174
817
|
if (projectLocations.length === 0) {
|
|
2175
818
|
throw validationError("No locations configured for this project");
|
|
2176
819
|
}
|
|
@@ -2339,6 +982,11 @@ async function runRoutes(app, opts) {
|
|
|
2339
982
|
return reply.send(loadRunDetail(app, run));
|
|
2340
983
|
});
|
|
2341
984
|
}
|
|
985
|
+
function parseRunTriggerRequest(value) {
|
|
986
|
+
const result = runTriggerRequestSchema.safeParse(value);
|
|
987
|
+
if (result.success) return result.data;
|
|
988
|
+
throw validationError("Invalid run trigger request", { issues: result.error.issues });
|
|
989
|
+
}
|
|
2342
990
|
function formatRun(row) {
|
|
2343
991
|
return {
|
|
2344
992
|
id: row.id,
|
|
@@ -2550,7 +1198,7 @@ async function deliverWebhook(target, payload, webhookSecret) {
|
|
|
2550
1198
|
const body = JSON.stringify(payload);
|
|
2551
1199
|
const isHttps = target.url.protocol === "https:";
|
|
2552
1200
|
const port = target.url.port ? Number(target.url.port) : isHttps ? 443 : 80;
|
|
2553
|
-
const
|
|
1201
|
+
const path15 = `${target.url.pathname}${target.url.search}`;
|
|
2554
1202
|
const headers = {
|
|
2555
1203
|
"Content-Length": String(Buffer.byteLength(body)),
|
|
2556
1204
|
"Content-Type": "application/json",
|
|
@@ -2566,7 +1214,7 @@ async function deliverWebhook(target, payload, webhookSecret) {
|
|
|
2566
1214
|
headers,
|
|
2567
1215
|
hostname: target.address,
|
|
2568
1216
|
method: "POST",
|
|
2569
|
-
path:
|
|
1217
|
+
path: path15,
|
|
2570
1218
|
port,
|
|
2571
1219
|
timeout: REQUEST_TIMEOUT_MS
|
|
2572
1220
|
};
|
|
@@ -3604,7 +2252,7 @@ var booleanSchema = { type: "boolean" };
|
|
|
3604
2252
|
var integerSchema = { type: "integer" };
|
|
3605
2253
|
var objectSchema = { type: "object", additionalProperties: true };
|
|
3606
2254
|
var stringArraySchema = { type: "array", items: stringSchema };
|
|
3607
|
-
var
|
|
2255
|
+
var googleConnectionTypeSchema = { type: "string", enum: ["gsc", "ga4"] };
|
|
3608
2256
|
var locationSchema = {
|
|
3609
2257
|
type: "object",
|
|
3610
2258
|
required: ["label", "city", "region", "country"],
|
|
@@ -3656,7 +2304,7 @@ var googleTypeParameter = {
|
|
|
3656
2304
|
in: "path",
|
|
3657
2305
|
required: true,
|
|
3658
2306
|
description: "Google connection type.",
|
|
3659
|
-
schema:
|
|
2307
|
+
schema: googleConnectionTypeSchema
|
|
3660
2308
|
};
|
|
3661
2309
|
var projectRunIdParameter = {
|
|
3662
2310
|
name: "runId",
|
|
@@ -4649,7 +3297,7 @@ var routeCatalog = [
|
|
|
4649
3297
|
type: "object",
|
|
4650
3298
|
required: ["type"],
|
|
4651
3299
|
properties: {
|
|
4652
|
-
type:
|
|
3300
|
+
type: googleConnectionTypeSchema,
|
|
4653
3301
|
propertyId: stringSchema,
|
|
4654
3302
|
publicUrl: stringSchema
|
|
4655
3303
|
}
|
|
@@ -6071,8 +4719,8 @@ async function openApiRoutes(app, opts = {}) {
|
|
|
6071
4719
|
return reply.type("application/json").send(buildOpenApiDocument(opts));
|
|
6072
4720
|
});
|
|
6073
4721
|
}
|
|
6074
|
-
function buildOperationId(method,
|
|
6075
|
-
const parts =
|
|
4722
|
+
function buildOperationId(method, path15) {
|
|
4723
|
+
const parts = path15.split("/").filter(Boolean).map((part) => {
|
|
6076
4724
|
if (part.startsWith("{") && part.endsWith("}")) {
|
|
6077
4725
|
return `by-${part.slice(1, -1)}`;
|
|
6078
4726
|
}
|
|
@@ -6594,7 +5242,7 @@ async function exchangeCode(clientId, clientSecret, code, redirectUri) {
|
|
|
6594
5242
|
const parsed = JSON.parse(body);
|
|
6595
5243
|
if (parsed.error) detail = parsed.error;
|
|
6596
5244
|
if (parsed.error_description) {
|
|
6597
|
-
const sanitized = parsed.error_description.replace(new RegExp(
|
|
5245
|
+
const sanitized = parsed.error_description.replace(new RegExp(escapeRegExp(clientId), "g"), "***").replace(new RegExp(escapeRegExp(clientSecret), "g"), "***").replace(new RegExp(escapeRegExp(code), "g"), "***");
|
|
6598
5246
|
detail += detail ? `: ${sanitized}` : sanitized;
|
|
6599
5247
|
}
|
|
6600
5248
|
} catch {
|
|
@@ -6604,7 +5252,7 @@ async function exchangeCode(clientId, clientSecret, code, redirectUri) {
|
|
|
6604
5252
|
}
|
|
6605
5253
|
return await res.json();
|
|
6606
5254
|
}
|
|
6607
|
-
function
|
|
5255
|
+
function escapeRegExp(str) {
|
|
6608
5256
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6609
5257
|
}
|
|
6610
5258
|
async function refreshAccessToken(clientId, clientSecret, currentRefreshToken) {
|
|
@@ -6632,7 +5280,7 @@ async function refreshAccessToken(clientId, clientSecret, currentRefreshToken) {
|
|
|
6632
5280
|
const parsed = JSON.parse(body);
|
|
6633
5281
|
if (parsed.error) detail = parsed.error;
|
|
6634
5282
|
if (parsed.error_description) {
|
|
6635
|
-
const sanitized = parsed.error_description.replace(new RegExp(
|
|
5283
|
+
const sanitized = parsed.error_description.replace(new RegExp(escapeRegExp(clientId), "g"), "***").replace(new RegExp(escapeRegExp(clientSecret), "g"), "***").replace(new RegExp(escapeRegExp(currentRefreshToken), "g"), "***");
|
|
6636
5284
|
detail += detail ? `: ${sanitized}` : sanitized;
|
|
6637
5285
|
}
|
|
6638
5286
|
} catch {
|
|
@@ -6946,13 +5594,13 @@ async function getAccessToken(clientEmail, privateKey) {
|
|
|
6946
5594
|
const body = await res.text().catch(() => "");
|
|
6947
5595
|
ga4Log("error", "token.failed", { httpStatus: res.status });
|
|
6948
5596
|
const detail = body.length <= 200 ? body : `${body.slice(0, 200)}... [truncated]`;
|
|
6949
|
-
const sanitizedDetail = detail.replace(new RegExp(
|
|
5597
|
+
const sanitizedDetail = detail.replace(new RegExp(escapeRegExp2(clientEmail), "g"), "***").replace(new RegExp(escapeRegExp2(privateKey.slice(0, 32)), "g"), "***");
|
|
6950
5598
|
throw new GA4ApiError(`Failed to get access token: ${sanitizedDetail}`, res.status);
|
|
6951
5599
|
}
|
|
6952
5600
|
const data = await res.json();
|
|
6953
5601
|
return data.access_token;
|
|
6954
5602
|
}
|
|
6955
|
-
function
|
|
5603
|
+
function escapeRegExp2(str) {
|
|
6956
5604
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6957
5605
|
}
|
|
6958
5606
|
async function runReport(accessToken, propertyId, request) {
|
|
@@ -8082,7 +6730,7 @@ function bingClientLog(level, action, ctx) {
|
|
|
8082
6730
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
8083
6731
|
stream.write(JSON.stringify(entry) + "\n");
|
|
8084
6732
|
}
|
|
8085
|
-
function
|
|
6733
|
+
function escapeRegExp3(str) {
|
|
8086
6734
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8087
6735
|
}
|
|
8088
6736
|
async function bingFetch(apiKey, endpoint, opts) {
|
|
@@ -8110,7 +6758,7 @@ async function bingFetch(apiKey, endpoint, opts) {
|
|
|
8110
6758
|
const body = await res.text();
|
|
8111
6759
|
bingClientLog("error", "http.error", { endpoint, method, httpStatus: res.status });
|
|
8112
6760
|
let detail = body.length <= 500 ? body : `${body.slice(0, 500)}... [truncated]`;
|
|
8113
|
-
detail = detail.replace(new RegExp(
|
|
6761
|
+
detail = detail.replace(new RegExp(escapeRegExp3(apiKey), "g"), "***");
|
|
8114
6762
|
throw new BingApiError(`Bing API error (${res.status}): ${detail}`, res.status);
|
|
8115
6763
|
}
|
|
8116
6764
|
const text = await res.text();
|
|
@@ -8654,12 +7302,12 @@ async function bingRoutes(app, opts) {
|
|
|
8654
7302
|
}
|
|
8655
7303
|
|
|
8656
7304
|
// ../api-routes/src/cdp.ts
|
|
8657
|
-
import
|
|
8658
|
-
import
|
|
8659
|
-
import
|
|
7305
|
+
import fs from "fs";
|
|
7306
|
+
import path from "path";
|
|
7307
|
+
import os from "os";
|
|
8660
7308
|
import { eq as eq16, and as and5 } from "drizzle-orm";
|
|
8661
7309
|
function getScreenshotDir() {
|
|
8662
|
-
return
|
|
7310
|
+
return path.join(os.homedir(), ".canonry", "screenshots");
|
|
8663
7311
|
}
|
|
8664
7312
|
async function cdpRoutes(app, opts) {
|
|
8665
7313
|
app.get("/screenshots/:snapshotId", async (request, reply) => {
|
|
@@ -8669,17 +7317,17 @@ async function cdpRoutes(app, opts) {
|
|
|
8669
7317
|
const err = notFound("Screenshot", snapshotId);
|
|
8670
7318
|
return reply.code(err.statusCode).send(err.toJSON());
|
|
8671
7319
|
}
|
|
8672
|
-
const base =
|
|
8673
|
-
const fullPath =
|
|
8674
|
-
if (!fullPath.startsWith(base +
|
|
7320
|
+
const base = path.resolve(getScreenshotDir());
|
|
7321
|
+
const fullPath = path.resolve(path.join(base, snapshot.screenshotPath));
|
|
7322
|
+
if (!fullPath.startsWith(base + path.sep) && fullPath !== base) {
|
|
8675
7323
|
const err = notFound("Screenshot", snapshotId);
|
|
8676
7324
|
return reply.code(err.statusCode).send(err.toJSON());
|
|
8677
7325
|
}
|
|
8678
|
-
if (!
|
|
7326
|
+
if (!fs.existsSync(fullPath)) {
|
|
8679
7327
|
const err = notFound("Screenshot file", snapshotId);
|
|
8680
7328
|
return reply.code(err.statusCode).send(err.toJSON());
|
|
8681
7329
|
}
|
|
8682
|
-
const stream =
|
|
7330
|
+
const stream = fs.createReadStream(fullPath);
|
|
8683
7331
|
return reply.type("image/png").send(stream);
|
|
8684
7332
|
});
|
|
8685
7333
|
app.put("/settings/cdp", async (request, reply) => {
|
|
@@ -9684,10 +8332,10 @@ function buildAuthErrorMessage(res, responseText) {
|
|
|
9684
8332
|
}
|
|
9685
8333
|
return "WordPress credentials are invalid or lack permission for this action";
|
|
9686
8334
|
}
|
|
9687
|
-
async function fetchJson(connection, siteUrl,
|
|
8335
|
+
async function fetchJson(connection, siteUrl, path15, init) {
|
|
9688
8336
|
if (siteUrl.startsWith("http:")) {
|
|
9689
8337
|
}
|
|
9690
|
-
const res = await fetch(`${normalizeSiteUrl(siteUrl)}${
|
|
8338
|
+
const res = await fetch(`${normalizeSiteUrl(siteUrl)}${path15}`, {
|
|
9691
8339
|
...init,
|
|
9692
8340
|
headers: {
|
|
9693
8341
|
"Authorization": `Basic ${encodeBasicAuth(connection.username, connection.appPassword)}`,
|
|
@@ -10202,12 +8850,12 @@ var CANONRY_SCHEMA_START = "<!-- canonry:schema:start -->";
|
|
|
10202
8850
|
var CANONRY_SCHEMA_END = "<!-- canonry:schema:end -->";
|
|
10203
8851
|
function stripCanonrySchema(content) {
|
|
10204
8852
|
const regex = new RegExp(
|
|
10205
|
-
`${
|
|
8853
|
+
`${escapeRegExp4(CANONRY_SCHEMA_START)}[\\s\\S]*?${escapeRegExp4(CANONRY_SCHEMA_END)}`,
|
|
10206
8854
|
"g"
|
|
10207
8855
|
);
|
|
10208
8856
|
return content.replace(regex, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
10209
8857
|
}
|
|
10210
|
-
function
|
|
8858
|
+
function escapeRegExp4(str) {
|
|
10211
8859
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10212
8860
|
}
|
|
10213
8861
|
function injectCanonrySchema(content, schemas) {
|
|
@@ -10314,7 +8962,7 @@ async function getSchemaStatus(connection, env) {
|
|
|
10314
8962
|
const thirdPartySchemas = [];
|
|
10315
8963
|
if (hasCanonryMarker) {
|
|
10316
8964
|
const markerRegex = new RegExp(
|
|
10317
|
-
`${
|
|
8965
|
+
`${escapeRegExp4(CANONRY_SCHEMA_START)}([\\s\\S]*?)${escapeRegExp4(CANONRY_SCHEMA_END)}`
|
|
10318
8966
|
);
|
|
10319
8967
|
const match = markerRegex.exec(rawContent);
|
|
10320
8968
|
if (match?.[1]) {
|
|
@@ -11108,13 +9756,13 @@ import crypto18 from "crypto";
|
|
|
11108
9756
|
import { and as and7, asc as asc2, desc as desc8, eq as eq18, sql as sql5 } from "drizzle-orm";
|
|
11109
9757
|
|
|
11110
9758
|
// ../integration-commoncrawl/src/constants.ts
|
|
11111
|
-
import
|
|
11112
|
-
import
|
|
9759
|
+
import os2 from "os";
|
|
9760
|
+
import path2 from "path";
|
|
11113
9761
|
var CC_BASE_URL = "https://data.commoncrawl.org/projects/hyperlinkgraph";
|
|
11114
|
-
var PLUGIN_DIR =
|
|
11115
|
-
var PLUGIN_PKG_JSON =
|
|
9762
|
+
var PLUGIN_DIR = path2.join(os2.homedir(), ".canonry", "plugins");
|
|
9763
|
+
var PLUGIN_PKG_JSON = path2.join(PLUGIN_DIR, "package.json");
|
|
11116
9764
|
var DUCKDB_SPEC = process.env.CANONRY_DUCKDB_SPEC ?? "@duckdb/node-api@1.4.4-r.3";
|
|
11117
|
-
var CC_CACHE_DIR = process.env.CANONRY_CC_CACHE_DIR ??
|
|
9765
|
+
var CC_CACHE_DIR = process.env.CANONRY_CC_CACHE_DIR ?? path2.join(os2.homedir(), ".canonry", "cache", "commoncrawl");
|
|
11118
9766
|
var RELEASE_ID_REGEX = /^cc-main-(\d{4})-(jan-feb-mar|apr-may-jun|jul-aug-sep|oct-nov-dec)$/;
|
|
11119
9767
|
function ccReleasePaths(release) {
|
|
11120
9768
|
const base = `${CC_BASE_URL}/${release}/domain`;
|
|
@@ -11144,8 +9792,8 @@ function isValidReleaseId(id) {
|
|
|
11144
9792
|
// ../integration-commoncrawl/src/downloader.ts
|
|
11145
9793
|
import { createHash } from "crypto";
|
|
11146
9794
|
import { createWriteStream } from "fs";
|
|
11147
|
-
import
|
|
11148
|
-
import
|
|
9795
|
+
import fs2 from "fs/promises";
|
|
9796
|
+
import path3 from "path";
|
|
11149
9797
|
import { pipeline } from "stream/promises";
|
|
11150
9798
|
import { Readable, Transform } from "stream";
|
|
11151
9799
|
async function downloadFile(opts) {
|
|
@@ -11153,7 +9801,7 @@ async function downloadFile(opts) {
|
|
|
11153
9801
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
11154
9802
|
const sidecarPath = `${opts.destPath}.sha256`;
|
|
11155
9803
|
try {
|
|
11156
|
-
const stat = await
|
|
9804
|
+
const stat = await fs2.stat(opts.destPath);
|
|
11157
9805
|
const sidecar = await readSidecar(sidecarPath);
|
|
11158
9806
|
const sha2562 = sidecar ?? await hashFile(opts.destPath);
|
|
11159
9807
|
if (!sidecar) await writeSidecar(sidecarPath, sha2562);
|
|
@@ -11161,7 +9809,7 @@ async function downloadFile(opts) {
|
|
|
11161
9809
|
} catch {
|
|
11162
9810
|
}
|
|
11163
9811
|
const partialPath = `${opts.destPath}.partial`;
|
|
11164
|
-
await
|
|
9812
|
+
await fs2.mkdir(path3.dirname(opts.destPath), { recursive: true });
|
|
11165
9813
|
await unlinkIfExists(partialPath);
|
|
11166
9814
|
const res = await fetchImpl(opts.url);
|
|
11167
9815
|
if (!res.ok || !res.body) {
|
|
@@ -11184,13 +9832,13 @@ async function downloadFile(opts) {
|
|
|
11184
9832
|
createWriteStream(partialPath)
|
|
11185
9833
|
);
|
|
11186
9834
|
const sha256 = hasher.digest("hex");
|
|
11187
|
-
await
|
|
9835
|
+
await fs2.rename(partialPath, opts.destPath);
|
|
11188
9836
|
await writeSidecar(sidecarPath, sha256);
|
|
11189
9837
|
return { bytes, sha256, cached: false, elapsedMs: Date.now() - start };
|
|
11190
9838
|
}
|
|
11191
9839
|
async function hashFile(filePath) {
|
|
11192
9840
|
const hasher = createHash("sha256");
|
|
11193
|
-
const handle = await
|
|
9841
|
+
const handle = await fs2.open(filePath, "r");
|
|
11194
9842
|
try {
|
|
11195
9843
|
const stream = handle.createReadStream();
|
|
11196
9844
|
for await (const chunk of stream) hasher.update(chunk);
|
|
@@ -11201,7 +9849,7 @@ async function hashFile(filePath) {
|
|
|
11201
9849
|
}
|
|
11202
9850
|
async function readSidecar(sidecarPath) {
|
|
11203
9851
|
try {
|
|
11204
|
-
const raw = await
|
|
9852
|
+
const raw = await fs2.readFile(sidecarPath, "utf8");
|
|
11205
9853
|
const trimmed = raw.trim();
|
|
11206
9854
|
return /^[0-9a-f]{64}$/i.test(trimmed) ? trimmed.toLowerCase() : null;
|
|
11207
9855
|
} catch {
|
|
@@ -11209,12 +9857,12 @@ async function readSidecar(sidecarPath) {
|
|
|
11209
9857
|
}
|
|
11210
9858
|
}
|
|
11211
9859
|
async function writeSidecar(sidecarPath, sha256) {
|
|
11212
|
-
await
|
|
9860
|
+
await fs2.writeFile(sidecarPath, `${sha256}
|
|
11213
9861
|
`);
|
|
11214
9862
|
}
|
|
11215
9863
|
async function unlinkIfExists(p) {
|
|
11216
9864
|
try {
|
|
11217
|
-
await
|
|
9865
|
+
await fs2.unlink(p);
|
|
11218
9866
|
} catch {
|
|
11219
9867
|
}
|
|
11220
9868
|
}
|
|
@@ -11225,20 +9873,20 @@ function parseContentLength(value) {
|
|
|
11225
9873
|
}
|
|
11226
9874
|
|
|
11227
9875
|
// ../integration-commoncrawl/src/plugin-resolver.ts
|
|
11228
|
-
import
|
|
9876
|
+
import fs3 from "fs";
|
|
11229
9877
|
import { createRequire as createRequire2 } from "module";
|
|
11230
|
-
import
|
|
9878
|
+
import path4 from "path";
|
|
11231
9879
|
function pluginDirFor(pkgJson) {
|
|
11232
|
-
return
|
|
9880
|
+
return path4.dirname(pkgJson);
|
|
11233
9881
|
}
|
|
11234
9882
|
function duckdbPkgJsonFor(pluginDir) {
|
|
11235
|
-
return
|
|
9883
|
+
return path4.join(pluginDir, "node_modules", "@duckdb", "node-api", "package.json");
|
|
11236
9884
|
}
|
|
11237
9885
|
function loadDuckdb(opts = {}) {
|
|
11238
9886
|
const pkgJson = opts.pluginPkgJson ?? PLUGIN_PKG_JSON;
|
|
11239
9887
|
const pluginDir = pluginDirFor(pkgJson);
|
|
11240
9888
|
const duckdbPkg = duckdbPkgJsonFor(pluginDir);
|
|
11241
|
-
if (!
|
|
9889
|
+
if (!fs3.existsSync(duckdbPkg)) {
|
|
11242
9890
|
throw missingDependency(
|
|
11243
9891
|
"@duckdb/node-api is not installed. Run `canonry backlinks install` to enable the backlinks feature.",
|
|
11244
9892
|
{ pluginDir }
|
|
@@ -11256,12 +9904,12 @@ function loadDuckdb(opts = {}) {
|
|
|
11256
9904
|
}
|
|
11257
9905
|
function isDuckdbInstalled(opts = {}) {
|
|
11258
9906
|
const pkgJson = opts.pluginPkgJson ?? PLUGIN_PKG_JSON;
|
|
11259
|
-
return
|
|
9907
|
+
return fs3.existsSync(duckdbPkgJsonFor(pluginDirFor(pkgJson)));
|
|
11260
9908
|
}
|
|
11261
9909
|
function readInstalledVersion(opts = {}) {
|
|
11262
9910
|
const pluginDir = opts.pluginPkgJson ? pluginDirFor(opts.pluginPkgJson) : PLUGIN_DIR;
|
|
11263
9911
|
try {
|
|
11264
|
-
const raw =
|
|
9912
|
+
const raw = fs3.readFileSync(duckdbPkgJsonFor(pluginDir), "utf8");
|
|
11265
9913
|
const pkg = JSON.parse(raw);
|
|
11266
9914
|
return pkg.version ?? null;
|
|
11267
9915
|
} catch {
|
|
@@ -11271,11 +9919,11 @@ function readInstalledVersion(opts = {}) {
|
|
|
11271
9919
|
|
|
11272
9920
|
// ../integration-commoncrawl/src/plugin-installer.ts
|
|
11273
9921
|
import { spawn } from "child_process";
|
|
11274
|
-
import
|
|
11275
|
-
import
|
|
9922
|
+
import fs4 from "fs/promises";
|
|
9923
|
+
import path5 from "path";
|
|
11276
9924
|
async function installDuckdb(opts = {}) {
|
|
11277
9925
|
const pluginDir = opts.pluginDir ?? PLUGIN_DIR;
|
|
11278
|
-
const pluginPkgJson =
|
|
9926
|
+
const pluginPkgJson = path5.join(pluginDir, "package.json");
|
|
11279
9927
|
const spec = opts.spec ?? DUCKDB_SPEC;
|
|
11280
9928
|
const pkgManager = opts.packageManager ?? "npm";
|
|
11281
9929
|
await ensurePluginDir(pluginDir, pluginPkgJson);
|
|
@@ -11291,12 +9939,12 @@ async function installDuckdb(opts = {}) {
|
|
|
11291
9939
|
return { alreadyPresent: false, version, path: pluginDir };
|
|
11292
9940
|
}
|
|
11293
9941
|
async function ensurePluginDir(pluginDir = PLUGIN_DIR, pluginPkgJson = PLUGIN_PKG_JSON) {
|
|
11294
|
-
await
|
|
9942
|
+
await fs4.mkdir(pluginDir, { recursive: true });
|
|
11295
9943
|
try {
|
|
11296
|
-
await
|
|
9944
|
+
await fs4.access(pluginPkgJson);
|
|
11297
9945
|
} catch {
|
|
11298
9946
|
const contents = JSON.stringify({ name: "canonry-plugins", private: true, dependencies: {} }, null, 2);
|
|
11299
|
-
await
|
|
9947
|
+
await fs4.writeFile(pluginPkgJson, `${contents}
|
|
11300
9948
|
`);
|
|
11301
9949
|
}
|
|
11302
9950
|
}
|
|
@@ -11389,8 +10037,8 @@ function quote(s) {
|
|
|
11389
10037
|
}
|
|
11390
10038
|
|
|
11391
10039
|
// ../integration-commoncrawl/src/cache.ts
|
|
11392
|
-
import
|
|
11393
|
-
import
|
|
10040
|
+
import fs5 from "fs";
|
|
10041
|
+
import path6 from "path";
|
|
11394
10042
|
function cacheRoot(opts = {}) {
|
|
11395
10043
|
return opts.cacheDir ?? CC_CACHE_DIR;
|
|
11396
10044
|
}
|
|
@@ -11400,18 +10048,18 @@ function directoryBytesAndLastUsed(dir) {
|
|
|
11400
10048
|
const walk = (p) => {
|
|
11401
10049
|
let stat;
|
|
11402
10050
|
try {
|
|
11403
|
-
stat =
|
|
10051
|
+
stat = fs5.statSync(p);
|
|
11404
10052
|
} catch {
|
|
11405
10053
|
return;
|
|
11406
10054
|
}
|
|
11407
10055
|
if (stat.isDirectory()) {
|
|
11408
10056
|
let entries;
|
|
11409
10057
|
try {
|
|
11410
|
-
entries =
|
|
10058
|
+
entries = fs5.readdirSync(p);
|
|
11411
10059
|
} catch {
|
|
11412
10060
|
return;
|
|
11413
10061
|
}
|
|
11414
|
-
for (const e of entries) walk(
|
|
10062
|
+
for (const e of entries) walk(path6.join(p, e));
|
|
11415
10063
|
} else if (stat.isFile()) {
|
|
11416
10064
|
bytes += stat.size;
|
|
11417
10065
|
const mtime = Math.max(stat.mtimeMs, stat.atimeMs);
|
|
@@ -11426,13 +10074,13 @@ function directoryBytesAndLastUsed(dir) {
|
|
|
11426
10074
|
}
|
|
11427
10075
|
function listCachedReleases(opts = {}) {
|
|
11428
10076
|
const root = cacheRoot(opts);
|
|
11429
|
-
if (!
|
|
11430
|
-
const entries =
|
|
10077
|
+
if (!fs5.existsSync(root)) return [];
|
|
10078
|
+
const entries = fs5.readdirSync(root, { withFileTypes: true });
|
|
11431
10079
|
const result = [];
|
|
11432
10080
|
for (const entry of entries) {
|
|
11433
10081
|
if (!entry.isDirectory()) continue;
|
|
11434
10082
|
if (!RELEASE_ID_REGEX.test(entry.name)) continue;
|
|
11435
|
-
const dir =
|
|
10083
|
+
const dir = path6.join(root, entry.name);
|
|
11436
10084
|
const stats = directoryBytesAndLastUsed(dir);
|
|
11437
10085
|
result.push({ release: entry.name, bytes: stats.bytes, lastUsedAt: stats.lastUsedAt });
|
|
11438
10086
|
}
|
|
@@ -11443,8 +10091,8 @@ function pruneCachedRelease(release, opts = {}) {
|
|
|
11443
10091
|
if (!RELEASE_ID_REGEX.test(release)) {
|
|
11444
10092
|
throw new Error(`Invalid release id: ${release}`);
|
|
11445
10093
|
}
|
|
11446
|
-
const dir =
|
|
11447
|
-
|
|
10094
|
+
const dir = path6.join(cacheRoot(opts), release);
|
|
10095
|
+
fs5.rmSync(dir, { recursive: true, force: true });
|
|
11448
10096
|
}
|
|
11449
10097
|
|
|
11450
10098
|
// ../api-routes/src/backlinks.ts
|
|
@@ -11787,7 +10435,7 @@ async function apiRoutes(app, opts) {
|
|
|
11787
10435
|
}
|
|
11788
10436
|
|
|
11789
10437
|
// src/server.ts
|
|
11790
|
-
import
|
|
10438
|
+
import os5 from "os";
|
|
11791
10439
|
|
|
11792
10440
|
// ../provider-gemini/src/normalize.ts
|
|
11793
10441
|
import { GoogleGenAI } from "@google/genai";
|
|
@@ -13175,8 +11823,8 @@ var localAdapter = {
|
|
|
13175
11823
|
};
|
|
13176
11824
|
|
|
13177
11825
|
// ../provider-cdp/src/adapter.ts
|
|
13178
|
-
import
|
|
13179
|
-
import
|
|
11826
|
+
import path8 from "path";
|
|
11827
|
+
import os3 from "os";
|
|
13180
11828
|
|
|
13181
11829
|
// ../provider-cdp/src/connection.ts
|
|
13182
11830
|
import CDP from "chrome-remote-interface";
|
|
@@ -13540,12 +12188,12 @@ function sleep2(ms) {
|
|
|
13540
12188
|
}
|
|
13541
12189
|
|
|
13542
12190
|
// ../provider-cdp/src/screenshot.ts
|
|
13543
|
-
import
|
|
13544
|
-
import
|
|
12191
|
+
import fs6 from "fs";
|
|
12192
|
+
import path7 from "path";
|
|
13545
12193
|
async function captureElementScreenshot(client, selector, outputPath) {
|
|
13546
|
-
const dir =
|
|
13547
|
-
if (!
|
|
13548
|
-
|
|
12194
|
+
const dir = path7.dirname(outputPath);
|
|
12195
|
+
if (!fs6.existsSync(dir)) {
|
|
12196
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
13549
12197
|
}
|
|
13550
12198
|
let clip;
|
|
13551
12199
|
try {
|
|
@@ -13579,7 +12227,7 @@ async function captureElementScreenshot(client, selector, outputPath) {
|
|
|
13579
12227
|
}
|
|
13580
12228
|
const { data } = await client.Page.captureScreenshot(screenshotParams);
|
|
13581
12229
|
const buffer = Buffer.from(data, "base64");
|
|
13582
|
-
|
|
12230
|
+
fs6.writeFileSync(outputPath, buffer);
|
|
13583
12231
|
return outputPath;
|
|
13584
12232
|
}
|
|
13585
12233
|
|
|
@@ -13640,7 +12288,7 @@ function getConnection(config) {
|
|
|
13640
12288
|
return conn;
|
|
13641
12289
|
}
|
|
13642
12290
|
function getScreenshotDir2() {
|
|
13643
|
-
return
|
|
12291
|
+
return path8.join(os3.homedir(), ".canonry", "screenshots");
|
|
13644
12292
|
}
|
|
13645
12293
|
var cdpChatgptAdapter = {
|
|
13646
12294
|
name: "cdp:chatgpt",
|
|
@@ -13704,7 +12352,7 @@ var cdpChatgptAdapter = {
|
|
|
13704
12352
|
const answerText = await target.extractAnswer(client);
|
|
13705
12353
|
const groundingSources = await target.extractCitations(client);
|
|
13706
12354
|
const screenshotId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
13707
|
-
const screenshotPath =
|
|
12355
|
+
const screenshotPath = path8.join(getScreenshotDir2(), `${screenshotId}.png`);
|
|
13708
12356
|
let capturedScreenshotPath;
|
|
13709
12357
|
try {
|
|
13710
12358
|
capturedScreenshotPath = await captureElementScreenshot(
|
|
@@ -14241,9 +12889,9 @@ function removeWordpressConnection(config, projectName) {
|
|
|
14241
12889
|
|
|
14242
12890
|
// src/job-runner.ts
|
|
14243
12891
|
import crypto19 from "crypto";
|
|
14244
|
-
import
|
|
14245
|
-
import
|
|
14246
|
-
import
|
|
12892
|
+
import fs7 from "fs";
|
|
12893
|
+
import path9 from "path";
|
|
12894
|
+
import os4 from "os";
|
|
14247
12895
|
import { and as and8, eq as eq19, inArray as inArray3, sql as sql6 } from "drizzle-orm";
|
|
14248
12896
|
|
|
14249
12897
|
// src/citation-utils.ts
|
|
@@ -14627,12 +13275,12 @@ var JobRunner = class {
|
|
|
14627
13275
|
competitorDomains
|
|
14628
13276
|
);
|
|
14629
13277
|
let screenshotRelPath = null;
|
|
14630
|
-
if (raw.screenshotPath &&
|
|
13278
|
+
if (raw.screenshotPath && fs7.existsSync(raw.screenshotPath)) {
|
|
14631
13279
|
const snapshotId = crypto19.randomUUID();
|
|
14632
|
-
const screenshotDir =
|
|
14633
|
-
if (!
|
|
14634
|
-
const destPath =
|
|
14635
|
-
|
|
13280
|
+
const screenshotDir = path9.join(os4.homedir(), ".canonry", "screenshots", runId);
|
|
13281
|
+
if (!fs7.existsSync(screenshotDir)) fs7.mkdirSync(screenshotDir, { recursive: true });
|
|
13282
|
+
const destPath = path9.join(screenshotDir, `${snapshotId}.png`);
|
|
13283
|
+
fs7.renameSync(raw.screenshotPath, destPath);
|
|
14636
13284
|
screenshotRelPath = `${runId}/${snapshotId}.png`;
|
|
14637
13285
|
this.db.insert(querySnapshots).values({
|
|
14638
13286
|
id: snapshotId,
|
|
@@ -15421,7 +14069,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
|
|
|
15421
14069
|
|
|
15422
14070
|
// src/commoncrawl-sync.ts
|
|
15423
14071
|
import crypto23 from "crypto";
|
|
15424
|
-
import
|
|
14072
|
+
import path10 from "path";
|
|
15425
14073
|
import { and as and11, eq as eq23, sql as sql8 } from "drizzle-orm";
|
|
15426
14074
|
var log6 = createLogger("CommonCrawlSync");
|
|
15427
14075
|
var INSERT_CHUNK_SIZE = 1e4;
|
|
@@ -15450,9 +14098,9 @@ async function executeReleaseSync(db, syncId, opts) {
|
|
|
15450
14098
|
error: null
|
|
15451
14099
|
}).where(eq23(ccReleaseSyncs.id, syncId)).run();
|
|
15452
14100
|
const paths = ccReleasePaths(release);
|
|
15453
|
-
const releaseCacheDir =
|
|
15454
|
-
const vertexPath =
|
|
15455
|
-
const edgesPath =
|
|
14101
|
+
const releaseCacheDir = path10.join(deps.cacheDir, release);
|
|
14102
|
+
const vertexPath = path10.join(releaseCacheDir, paths.vertexFilename);
|
|
14103
|
+
const edgesPath = path10.join(releaseCacheDir, paths.edgesFilename);
|
|
15456
14104
|
const [vertex, edges] = await Promise.all([
|
|
15457
14105
|
deps.downloadFile({ url: paths.vertexUrl, destPath: vertexPath }),
|
|
15458
14106
|
deps.downloadFile({ url: paths.edgesUrl, destPath: edgesPath })
|
|
@@ -15612,7 +14260,7 @@ function computeSummary(rows) {
|
|
|
15612
14260
|
|
|
15613
14261
|
// src/backlink-extract.ts
|
|
15614
14262
|
import crypto24 from "crypto";
|
|
15615
|
-
import
|
|
14263
|
+
import fs8 from "fs";
|
|
15616
14264
|
import { and as and12, desc as desc10, eq as eq24 } from "drizzle-orm";
|
|
15617
14265
|
var log7 = createLogger("BacklinkExtract");
|
|
15618
14266
|
function defaultDeps2() {
|
|
@@ -15641,7 +14289,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
|
|
|
15641
14289
|
if (!sync.vertexPath || !sync.edgesPath) {
|
|
15642
14290
|
throw new Error(`Release ${sync.release} is missing cached file paths`);
|
|
15643
14291
|
}
|
|
15644
|
-
if (!
|
|
14292
|
+
if (!fs8.existsSync(sync.vertexPath) || !fs8.existsSync(sync.edgesPath)) {
|
|
15645
14293
|
throw new Error(
|
|
15646
14294
|
`Cache for release ${sync.release} is missing from disk (expected at ${sync.vertexPath}). The sync record exists in the database, but the ~16 GB dump was deleted or never present on this machine. Re-sync this release from the Backlinks admin page to restore the cache.`
|
|
15647
14295
|
);
|
|
@@ -16160,8 +14808,8 @@ import crypto27 from "crypto";
|
|
|
16160
14808
|
import { eq as eq28 } from "drizzle-orm";
|
|
16161
14809
|
|
|
16162
14810
|
// src/agent/session.ts
|
|
16163
|
-
import
|
|
16164
|
-
import
|
|
14811
|
+
import fs11 from "fs";
|
|
14812
|
+
import path13 from "path";
|
|
16165
14813
|
import { Agent } from "@mariozechner/pi-agent-core";
|
|
16166
14814
|
import { registerBuiltInApiProviders } from "@mariozechner/pi-ai";
|
|
16167
14815
|
|
|
@@ -16262,26 +14910,26 @@ function buildAgentProvidersResponse(config) {
|
|
|
16262
14910
|
}
|
|
16263
14911
|
|
|
16264
14912
|
// src/agent/skill-paths.ts
|
|
16265
|
-
import
|
|
16266
|
-
import
|
|
14913
|
+
import fs9 from "fs";
|
|
14914
|
+
import path11 from "path";
|
|
16267
14915
|
import { fileURLToPath } from "url";
|
|
16268
14916
|
function resolveAeroSkillDir(pkgDir) {
|
|
16269
|
-
const here = pkgDir ??
|
|
14917
|
+
const here = pkgDir ?? path11.dirname(fileURLToPath(import.meta.url));
|
|
16270
14918
|
const candidates = [
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
14919
|
+
path11.join(here, "../assets/agent-workspace/skills/aero"),
|
|
14920
|
+
path11.join(here, "../../assets/agent-workspace/skills/aero"),
|
|
14921
|
+
path11.join(here, "../../../../skills/aero")
|
|
16274
14922
|
];
|
|
16275
14923
|
for (const candidate of candidates) {
|
|
16276
|
-
if (
|
|
14924
|
+
if (fs9.existsSync(path11.join(candidate, "SKILL.md"))) return candidate;
|
|
16277
14925
|
}
|
|
16278
14926
|
throw new Error(`Aero skill not found. Searched:
|
|
16279
14927
|
${candidates.join("\n ")}`);
|
|
16280
14928
|
}
|
|
16281
14929
|
|
|
16282
14930
|
// src/agent/skill-tools.ts
|
|
16283
|
-
import
|
|
16284
|
-
import
|
|
14931
|
+
import fs10 from "fs";
|
|
14932
|
+
import path12 from "path";
|
|
16285
14933
|
import { Type } from "@sinclair/typebox";
|
|
16286
14934
|
var MAX_DOC_CHARS = 2e4;
|
|
16287
14935
|
function textResult(details) {
|
|
@@ -16302,13 +14950,13 @@ function parseDescription(body) {
|
|
|
16302
14950
|
return "(no description)";
|
|
16303
14951
|
}
|
|
16304
14952
|
function scanSkillDocs(skillDir) {
|
|
16305
|
-
const refsDir =
|
|
16306
|
-
if (!
|
|
14953
|
+
const refsDir = path12.join(skillDir ?? resolveAeroSkillDir(), "references");
|
|
14954
|
+
if (!fs10.existsSync(refsDir)) return [];
|
|
16307
14955
|
const entries = [];
|
|
16308
|
-
for (const file of
|
|
14956
|
+
for (const file of fs10.readdirSync(refsDir)) {
|
|
16309
14957
|
if (!file.endsWith(".md")) continue;
|
|
16310
|
-
const filePath =
|
|
16311
|
-
const body =
|
|
14958
|
+
const filePath = path12.join(refsDir, file);
|
|
14959
|
+
const body = fs10.readFileSync(filePath, "utf-8");
|
|
16312
14960
|
entries.push({
|
|
16313
14961
|
slug: file.replace(/\.md$/, ""),
|
|
16314
14962
|
description: parseDescription(body),
|
|
@@ -16351,8 +14999,8 @@ function buildReadSkillDocTool() {
|
|
|
16351
14999
|
availableSlugs: docs.map((d) => d.slug)
|
|
16352
15000
|
});
|
|
16353
15001
|
}
|
|
16354
|
-
const filePath =
|
|
16355
|
-
const content =
|
|
15002
|
+
const filePath = path12.join(skillDir, "references", `${match.slug}.md`);
|
|
15003
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
16356
15004
|
if (content.length > MAX_DOC_CHARS) {
|
|
16357
15005
|
return textResult({
|
|
16358
15006
|
slug: match.slug,
|
|
@@ -16906,10 +15554,10 @@ function ensureBuiltinsRegistered() {
|
|
|
16906
15554
|
}
|
|
16907
15555
|
function loadAeroSystemPrompt(pkgDir) {
|
|
16908
15556
|
const skillDir = resolveAeroSkillDir(pkgDir);
|
|
16909
|
-
const skillBody =
|
|
16910
|
-
const soulPath =
|
|
16911
|
-
if (!
|
|
16912
|
-
const soulBody =
|
|
15557
|
+
const skillBody = fs11.readFileSync(path13.join(skillDir, "SKILL.md"), "utf-8");
|
|
15558
|
+
const soulPath = path13.join(skillDir, "soul.md");
|
|
15559
|
+
if (!fs11.existsSync(soulPath)) return skillBody;
|
|
15560
|
+
const soulBody = fs11.readFileSync(soulPath, "utf-8");
|
|
16913
15561
|
return `${soulBody.trimEnd()}
|
|
16914
15562
|
|
|
16915
15563
|
---
|
|
@@ -17698,593 +16346,6 @@ function registerAgentRoutes(app, opts) {
|
|
|
17698
16346
|
);
|
|
17699
16347
|
}
|
|
17700
16348
|
|
|
17701
|
-
// src/client.ts
|
|
17702
|
-
function createApiClient() {
|
|
17703
|
-
const config = loadConfig();
|
|
17704
|
-
const basePathResolved = !!config.basePath || "CANONRY_BASE_PATH" in process.env;
|
|
17705
|
-
return new ApiClient(config.apiUrl, config.apiKey, { skipProbe: basePathResolved });
|
|
17706
|
-
}
|
|
17707
|
-
var ApiClient = class {
|
|
17708
|
-
baseUrl;
|
|
17709
|
-
originUrl;
|
|
17710
|
-
apiKey;
|
|
17711
|
-
probePromise = null;
|
|
17712
|
-
probeSkipped;
|
|
17713
|
-
constructor(baseUrl, apiKey, opts) {
|
|
17714
|
-
this.originUrl = baseUrl.replace(/\/$/, "");
|
|
17715
|
-
this.baseUrl = this.originUrl + "/api/v1";
|
|
17716
|
-
this.apiKey = apiKey;
|
|
17717
|
-
this.probeSkipped = opts?.skipProbe ?? false;
|
|
17718
|
-
}
|
|
17719
|
-
/**
|
|
17720
|
-
* On first API call, probe /health to auto-discover basePath when the user
|
|
17721
|
-
* hasn't configured one locally. This lets `canonry run` in a separate shell
|
|
17722
|
-
* discover that the server is running at e.g. /canonry/ without requiring
|
|
17723
|
-
* config.yaml edits or CANONRY_BASE_PATH in every shell.
|
|
17724
|
-
*/
|
|
17725
|
-
probeBasePath() {
|
|
17726
|
-
if (this.probeSkipped) return Promise.resolve();
|
|
17727
|
-
if (!this.probePromise) {
|
|
17728
|
-
this.probePromise = (async () => {
|
|
17729
|
-
try {
|
|
17730
|
-
const origin = new URL(this.originUrl).origin;
|
|
17731
|
-
const res = await fetch(`${origin}/health`, {
|
|
17732
|
-
signal: AbortSignal.timeout(2e3)
|
|
17733
|
-
});
|
|
17734
|
-
if (res.ok) {
|
|
17735
|
-
const body = await res.json();
|
|
17736
|
-
if (body.basePath && typeof body.basePath === "string") {
|
|
17737
|
-
const normalized = "/" + body.basePath.replace(/^\/|\/$/g, "");
|
|
17738
|
-
if (normalized !== "/") {
|
|
17739
|
-
this.originUrl = origin + normalized;
|
|
17740
|
-
this.baseUrl = this.originUrl + "/api/v1";
|
|
17741
|
-
}
|
|
17742
|
-
}
|
|
17743
|
-
}
|
|
17744
|
-
} catch {
|
|
17745
|
-
}
|
|
17746
|
-
})();
|
|
17747
|
-
}
|
|
17748
|
-
return this.probePromise;
|
|
17749
|
-
}
|
|
17750
|
-
async request(method, path16, body) {
|
|
17751
|
-
await this.probeBasePath();
|
|
17752
|
-
const url = `${this.baseUrl}${path16}`;
|
|
17753
|
-
const serializedBody = body != null ? JSON.stringify(body) : void 0;
|
|
17754
|
-
const headers = {
|
|
17755
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
17756
|
-
"Accept": "application/json",
|
|
17757
|
-
...serializedBody != null ? { "Content-Type": "application/json" } : {}
|
|
17758
|
-
};
|
|
17759
|
-
let res;
|
|
17760
|
-
try {
|
|
17761
|
-
res = await fetch(url, {
|
|
17762
|
-
method,
|
|
17763
|
-
headers,
|
|
17764
|
-
body: serializedBody
|
|
17765
|
-
});
|
|
17766
|
-
} catch (err) {
|
|
17767
|
-
if (err instanceof CliError) throw err;
|
|
17768
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
17769
|
-
if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("connect ECONNREFUSED")) {
|
|
17770
|
-
throw new CliError({
|
|
17771
|
-
code: "CONNECTION_ERROR",
|
|
17772
|
-
message: `Could not connect to canonry server at ${this.baseUrl.replace("/api/v1", "")}. Start it with "canonry serve" (or "canonry serve &" to run in background).`,
|
|
17773
|
-
exitCode: EXIT_SYSTEM_ERROR
|
|
17774
|
-
});
|
|
17775
|
-
}
|
|
17776
|
-
throw new CliError({ code: "CONNECTION_ERROR", message: msg, exitCode: EXIT_SYSTEM_ERROR });
|
|
17777
|
-
}
|
|
17778
|
-
if (!res.ok) {
|
|
17779
|
-
let errorBody;
|
|
17780
|
-
try {
|
|
17781
|
-
errorBody = await res.json();
|
|
17782
|
-
} catch {
|
|
17783
|
-
errorBody = { error: { code: "UNKNOWN", message: res.statusText } };
|
|
17784
|
-
}
|
|
17785
|
-
const errorObj = errorBody && typeof errorBody === "object" && "error" in errorBody && errorBody.error && typeof errorBody.error === "object" ? errorBody.error : null;
|
|
17786
|
-
const msg = errorObj?.message ? String(errorObj.message) : `HTTP ${res.status}: ${res.statusText}`;
|
|
17787
|
-
const code = errorObj?.code ? String(errorObj.code) : "API_ERROR";
|
|
17788
|
-
const exitCode = res.status >= 500 ? EXIT_SYSTEM_ERROR : EXIT_USER_ERROR;
|
|
17789
|
-
throw new CliError({ code, message: msg, exitCode, details: { httpStatus: res.status } });
|
|
17790
|
-
}
|
|
17791
|
-
if (res.status === 204) {
|
|
17792
|
-
return void 0;
|
|
17793
|
-
}
|
|
17794
|
-
return await res.json();
|
|
17795
|
-
}
|
|
17796
|
-
async getAgentTranscript(project) {
|
|
17797
|
-
return this.request(
|
|
17798
|
-
"GET",
|
|
17799
|
-
`/projects/${encodeURIComponent(project)}/agent/transcript`
|
|
17800
|
-
);
|
|
17801
|
-
}
|
|
17802
|
-
async resetAgentTranscript(project) {
|
|
17803
|
-
await this.request(
|
|
17804
|
-
"DELETE",
|
|
17805
|
-
`/projects/${encodeURIComponent(project)}/agent/transcript`
|
|
17806
|
-
);
|
|
17807
|
-
}
|
|
17808
|
-
async listAgentProviders(project) {
|
|
17809
|
-
return this.request(
|
|
17810
|
-
"GET",
|
|
17811
|
-
`/projects/${encodeURIComponent(project)}/agent/providers`
|
|
17812
|
-
);
|
|
17813
|
-
}
|
|
17814
|
-
async listAgentMemory(project) {
|
|
17815
|
-
return this.request(
|
|
17816
|
-
"GET",
|
|
17817
|
-
`/projects/${encodeURIComponent(project)}/agent/memory`
|
|
17818
|
-
);
|
|
17819
|
-
}
|
|
17820
|
-
async setAgentMemory(project, body) {
|
|
17821
|
-
return this.request(
|
|
17822
|
-
"PUT",
|
|
17823
|
-
`/projects/${encodeURIComponent(project)}/agent/memory`,
|
|
17824
|
-
body
|
|
17825
|
-
);
|
|
17826
|
-
}
|
|
17827
|
-
async forgetAgentMemory(project, key) {
|
|
17828
|
-
return this.request(
|
|
17829
|
-
"DELETE",
|
|
17830
|
-
`/projects/${encodeURIComponent(project)}/agent/memory`,
|
|
17831
|
-
{ key }
|
|
17832
|
-
);
|
|
17833
|
-
}
|
|
17834
|
-
/**
|
|
17835
|
-
* POST a request whose response body the caller intends to consume as a
|
|
17836
|
-
* stream (e.g. the Aero agent SSE endpoint). Shares the probe + auth +
|
|
17837
|
-
* structured-error behavior of `request()`; the caller reads `res.body`
|
|
17838
|
-
* and releases the response when done.
|
|
17839
|
-
*/
|
|
17840
|
-
async streamPost(path16, body, signal) {
|
|
17841
|
-
await this.probeBasePath();
|
|
17842
|
-
const url = `${this.baseUrl}${path16}`;
|
|
17843
|
-
const headers = {
|
|
17844
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
17845
|
-
"Content-Type": "application/json",
|
|
17846
|
-
Accept: "text/event-stream"
|
|
17847
|
-
};
|
|
17848
|
-
let res;
|
|
17849
|
-
try {
|
|
17850
|
-
res = await fetch(url, {
|
|
17851
|
-
method: "POST",
|
|
17852
|
-
headers,
|
|
17853
|
-
body: JSON.stringify(body ?? {}),
|
|
17854
|
-
signal
|
|
17855
|
-
});
|
|
17856
|
-
} catch (err) {
|
|
17857
|
-
if (err instanceof CliError) throw err;
|
|
17858
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
17859
|
-
if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("connect ECONNREFUSED")) {
|
|
17860
|
-
throw new CliError({
|
|
17861
|
-
code: "CONNECTION_ERROR",
|
|
17862
|
-
message: `Could not connect to canonry server at ${this.baseUrl.replace("/api/v1", "")}. Start it with "canonry serve" (or "canonry serve &" to run in background).`,
|
|
17863
|
-
exitCode: EXIT_SYSTEM_ERROR
|
|
17864
|
-
});
|
|
17865
|
-
}
|
|
17866
|
-
throw new CliError({ code: "CONNECTION_ERROR", message: msg, exitCode: EXIT_SYSTEM_ERROR });
|
|
17867
|
-
}
|
|
17868
|
-
if (!res.ok || !res.body) {
|
|
17869
|
-
let errorBody;
|
|
17870
|
-
try {
|
|
17871
|
-
errorBody = await res.json();
|
|
17872
|
-
} catch {
|
|
17873
|
-
errorBody = { error: { code: "UNKNOWN", message: res.statusText } };
|
|
17874
|
-
}
|
|
17875
|
-
const errorObj = errorBody && typeof errorBody === "object" && "error" in errorBody && errorBody.error ? errorBody.error : null;
|
|
17876
|
-
const msg = errorObj?.message ? String(errorObj.message) : `HTTP ${res.status}: ${res.statusText}`;
|
|
17877
|
-
const code = errorObj?.code ? String(errorObj.code) : "API_ERROR";
|
|
17878
|
-
const exitCode = res.status >= 500 ? EXIT_SYSTEM_ERROR : EXIT_USER_ERROR;
|
|
17879
|
-
throw new CliError({ code, message: msg, exitCode, details: { httpStatus: res.status } });
|
|
17880
|
-
}
|
|
17881
|
-
return res;
|
|
17882
|
-
}
|
|
17883
|
-
async putProject(name, body) {
|
|
17884
|
-
return this.request("PUT", `/projects/${encodeURIComponent(name)}`, body);
|
|
17885
|
-
}
|
|
17886
|
-
async listProjects() {
|
|
17887
|
-
return this.request("GET", "/projects");
|
|
17888
|
-
}
|
|
17889
|
-
async getProject(name) {
|
|
17890
|
-
return this.request("GET", `/projects/${encodeURIComponent(name)}`);
|
|
17891
|
-
}
|
|
17892
|
-
async deleteProject(name) {
|
|
17893
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(name)}`);
|
|
17894
|
-
}
|
|
17895
|
-
async putKeywords(project, keywords2) {
|
|
17896
|
-
await this.request("PUT", `/projects/${encodeURIComponent(project)}/keywords`, { keywords: keywords2 });
|
|
17897
|
-
}
|
|
17898
|
-
async listKeywords(project) {
|
|
17899
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/keywords`);
|
|
17900
|
-
}
|
|
17901
|
-
async deleteKeywords(project, keywords2) {
|
|
17902
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/keywords`, { keywords: keywords2 });
|
|
17903
|
-
}
|
|
17904
|
-
async appendKeywords(project, keywords2) {
|
|
17905
|
-
await this.request("POST", `/projects/${encodeURIComponent(project)}/keywords`, { keywords: keywords2 });
|
|
17906
|
-
}
|
|
17907
|
-
async putCompetitors(project, competitors2) {
|
|
17908
|
-
await this.request("PUT", `/projects/${encodeURIComponent(project)}/competitors`, { competitors: competitors2 });
|
|
17909
|
-
}
|
|
17910
|
-
async listCompetitors(project) {
|
|
17911
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/competitors`);
|
|
17912
|
-
}
|
|
17913
|
-
async triggerRun(project, body) {
|
|
17914
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/runs`, body ?? {});
|
|
17915
|
-
}
|
|
17916
|
-
async listRuns(project, limit) {
|
|
17917
|
-
const query = limit != null ? `?limit=${encodeURIComponent(String(limit))}` : "";
|
|
17918
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/runs${query}`);
|
|
17919
|
-
}
|
|
17920
|
-
async getLatestRun(project) {
|
|
17921
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/runs/latest`);
|
|
17922
|
-
}
|
|
17923
|
-
async getRun(id) {
|
|
17924
|
-
return this.request("GET", `/runs/${encodeURIComponent(id)}`);
|
|
17925
|
-
}
|
|
17926
|
-
async cancelRun(id) {
|
|
17927
|
-
return this.request("POST", `/runs/${encodeURIComponent(id)}/cancel`);
|
|
17928
|
-
}
|
|
17929
|
-
async getTimeline(project) {
|
|
17930
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/timeline`);
|
|
17931
|
-
}
|
|
17932
|
-
async getHistory(project) {
|
|
17933
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/history`);
|
|
17934
|
-
}
|
|
17935
|
-
async getExport(project) {
|
|
17936
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/export`);
|
|
17937
|
-
}
|
|
17938
|
-
async apply(config) {
|
|
17939
|
-
return this.request("POST", "/apply", config);
|
|
17940
|
-
}
|
|
17941
|
-
async getStatus(project) {
|
|
17942
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}`);
|
|
17943
|
-
}
|
|
17944
|
-
async getSettings() {
|
|
17945
|
-
return this.request("GET", "/settings");
|
|
17946
|
-
}
|
|
17947
|
-
async createSnapshot(body) {
|
|
17948
|
-
return this.request("POST", "/snapshot", body);
|
|
17949
|
-
}
|
|
17950
|
-
async updateProvider(name, body) {
|
|
17951
|
-
return this.request("PUT", `/settings/providers/${encodeURIComponent(name)}`, body);
|
|
17952
|
-
}
|
|
17953
|
-
async putSchedule(project, body) {
|
|
17954
|
-
return this.request("PUT", `/projects/${encodeURIComponent(project)}/schedule`, body);
|
|
17955
|
-
}
|
|
17956
|
-
async getSchedule(project) {
|
|
17957
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/schedule`);
|
|
17958
|
-
}
|
|
17959
|
-
async deleteSchedule(project) {
|
|
17960
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/schedule`);
|
|
17961
|
-
}
|
|
17962
|
-
async createNotification(project, body) {
|
|
17963
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/notifications`, body);
|
|
17964
|
-
}
|
|
17965
|
-
async listNotifications(project) {
|
|
17966
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/notifications`);
|
|
17967
|
-
}
|
|
17968
|
-
async deleteNotification(project, id) {
|
|
17969
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/notifications/${encodeURIComponent(id)}`);
|
|
17970
|
-
}
|
|
17971
|
-
async testNotification(project, id) {
|
|
17972
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/notifications/${encodeURIComponent(id)}/test`);
|
|
17973
|
-
}
|
|
17974
|
-
async addLocation(project, body) {
|
|
17975
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/locations`, body);
|
|
17976
|
-
}
|
|
17977
|
-
async listLocations(project) {
|
|
17978
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/locations`);
|
|
17979
|
-
}
|
|
17980
|
-
async removeLocation(project, label) {
|
|
17981
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/locations/${encodeURIComponent(label)}`);
|
|
17982
|
-
}
|
|
17983
|
-
async setDefaultLocation(project, label) {
|
|
17984
|
-
return this.request("PUT", `/projects/${encodeURIComponent(project)}/locations/default`, { label });
|
|
17985
|
-
}
|
|
17986
|
-
async getTelemetry() {
|
|
17987
|
-
return this.request("GET", "/telemetry");
|
|
17988
|
-
}
|
|
17989
|
-
async updateTelemetry(enabled) {
|
|
17990
|
-
return this.request("PUT", "/telemetry", { enabled });
|
|
17991
|
-
}
|
|
17992
|
-
async generateKeywords(project, provider, count) {
|
|
17993
|
-
return this.request(
|
|
17994
|
-
"POST",
|
|
17995
|
-
`/projects/${encodeURIComponent(project)}/keywords/generate`,
|
|
17996
|
-
{ provider, count }
|
|
17997
|
-
);
|
|
17998
|
-
}
|
|
17999
|
-
// Google connection management
|
|
18000
|
-
async googleConnect(project, body) {
|
|
18001
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/connect`, body);
|
|
18002
|
-
}
|
|
18003
|
-
async googleConnections(project) {
|
|
18004
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/connections`);
|
|
18005
|
-
}
|
|
18006
|
-
async googleDisconnect(project, type) {
|
|
18007
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/google/connections/${encodeURIComponent(type)}`);
|
|
18008
|
-
}
|
|
18009
|
-
async googleProperties(project) {
|
|
18010
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/properties`);
|
|
18011
|
-
}
|
|
18012
|
-
async googleSetProperty(project, type, propertyId) {
|
|
18013
|
-
return this.request("PUT", `/projects/${encodeURIComponent(project)}/google/connections/${encodeURIComponent(type)}/property`, { propertyId });
|
|
18014
|
-
}
|
|
18015
|
-
async googleSetSitemap(project, type, sitemapUrl) {
|
|
18016
|
-
return this.request("PUT", `/projects/${encodeURIComponent(project)}/google/connections/${encodeURIComponent(type)}/sitemap`, { sitemapUrl });
|
|
18017
|
-
}
|
|
18018
|
-
// GSC data
|
|
18019
|
-
async gscSync(project, body) {
|
|
18020
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/gsc/sync`, body ?? {});
|
|
18021
|
-
}
|
|
18022
|
-
async gscPerformance(project, params) {
|
|
18023
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18024
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/performance${qs}`);
|
|
18025
|
-
}
|
|
18026
|
-
async gscInspect(project, url) {
|
|
18027
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/gsc/inspect`, { url });
|
|
18028
|
-
}
|
|
18029
|
-
async gscInspections(project, params) {
|
|
18030
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18031
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/inspections${qs}`);
|
|
18032
|
-
}
|
|
18033
|
-
async gscDeindexed(project) {
|
|
18034
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/deindexed`);
|
|
18035
|
-
}
|
|
18036
|
-
async gscCoverage(project) {
|
|
18037
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/coverage`);
|
|
18038
|
-
}
|
|
18039
|
-
async gscCoverageHistory(project, params) {
|
|
18040
|
-
const qs = params?.limit != null ? `?limit=${params.limit}` : "";
|
|
18041
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/coverage/history${qs}`);
|
|
18042
|
-
}
|
|
18043
|
-
async gscInspectSitemap(project, body) {
|
|
18044
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/gsc/inspect-sitemap`, body ?? {});
|
|
18045
|
-
}
|
|
18046
|
-
async gscSitemaps(project) {
|
|
18047
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/google/gsc/sitemaps`);
|
|
18048
|
-
}
|
|
18049
|
-
async gscDiscoverSitemaps(project) {
|
|
18050
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/gsc/discover-sitemaps`, {});
|
|
18051
|
-
}
|
|
18052
|
-
// Analytics
|
|
18053
|
-
async getAnalyticsMetrics(project, window) {
|
|
18054
|
-
const qs = window ? `?window=${encodeURIComponent(window)}` : "";
|
|
18055
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/analytics/metrics${qs}`);
|
|
18056
|
-
}
|
|
18057
|
-
async getAnalyticsGaps(project, window) {
|
|
18058
|
-
const qs = window ? `?window=${encodeURIComponent(window)}` : "";
|
|
18059
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/analytics/gaps${qs}`);
|
|
18060
|
-
}
|
|
18061
|
-
async getAnalyticsSources(project, window) {
|
|
18062
|
-
const qs = window ? `?window=${encodeURIComponent(window)}` : "";
|
|
18063
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/analytics/sources${qs}`);
|
|
18064
|
-
}
|
|
18065
|
-
// Google Indexing API
|
|
18066
|
-
async googleRequestIndexing(project, body) {
|
|
18067
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/google/indexing/request`, body);
|
|
18068
|
-
}
|
|
18069
|
-
// Bing Webmaster Tools
|
|
18070
|
-
async bingConnect(project, body) {
|
|
18071
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/bing/connect`, body);
|
|
18072
|
-
}
|
|
18073
|
-
async bingDisconnect(project) {
|
|
18074
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/bing/disconnect`);
|
|
18075
|
-
}
|
|
18076
|
-
async bingStatus(project) {
|
|
18077
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/bing/status`);
|
|
18078
|
-
}
|
|
18079
|
-
async bingSites(project) {
|
|
18080
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/bing/sites`);
|
|
18081
|
-
}
|
|
18082
|
-
async bingSetSite(project, siteUrl) {
|
|
18083
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/bing/set-site`, { siteUrl });
|
|
18084
|
-
}
|
|
18085
|
-
async bingCoverage(project) {
|
|
18086
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/bing/coverage`);
|
|
18087
|
-
}
|
|
18088
|
-
async bingCoverageHistory(project, params) {
|
|
18089
|
-
const qs = params?.limit != null ? `?limit=${params.limit}` : "";
|
|
18090
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/bing/coverage/history${qs}`);
|
|
18091
|
-
}
|
|
18092
|
-
async bingInspections(project, params) {
|
|
18093
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18094
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/bing/inspections${qs}`);
|
|
18095
|
-
}
|
|
18096
|
-
async bingInspectUrl(project, url) {
|
|
18097
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/bing/inspect-url`, { url });
|
|
18098
|
-
}
|
|
18099
|
-
async bingInspectSitemap(project, body) {
|
|
18100
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/bing/inspect-sitemap`, body ?? {});
|
|
18101
|
-
}
|
|
18102
|
-
async bingRequestIndexing(project, body) {
|
|
18103
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/bing/request-indexing`, body);
|
|
18104
|
-
}
|
|
18105
|
-
async bingPerformance(project, params) {
|
|
18106
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18107
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/bing/performance${qs}`);
|
|
18108
|
-
}
|
|
18109
|
-
// CDP browser provider
|
|
18110
|
-
async getCdpStatus() {
|
|
18111
|
-
return this.request("GET", "/cdp/status");
|
|
18112
|
-
}
|
|
18113
|
-
async cdpScreenshot(query, targets) {
|
|
18114
|
-
return this.request("POST", "/cdp/screenshot", { query, targets });
|
|
18115
|
-
}
|
|
18116
|
-
async getBrowserDiff(project, runId) {
|
|
18117
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/runs/${encodeURIComponent(runId)}/browser-diff`);
|
|
18118
|
-
}
|
|
18119
|
-
// Google Analytics 4
|
|
18120
|
-
async gaConnect(project, body) {
|
|
18121
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/ga/connect`, body);
|
|
18122
|
-
}
|
|
18123
|
-
async gaDisconnect(project) {
|
|
18124
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/ga/disconnect`);
|
|
18125
|
-
}
|
|
18126
|
-
async gaStatus(project) {
|
|
18127
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/status`);
|
|
18128
|
-
}
|
|
18129
|
-
async gaSync(project, body) {
|
|
18130
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/ga/sync`, body ?? {});
|
|
18131
|
-
}
|
|
18132
|
-
async gaTraffic(project, params) {
|
|
18133
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18134
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/traffic${qs}`);
|
|
18135
|
-
}
|
|
18136
|
-
async gaCoverage(project) {
|
|
18137
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/coverage`);
|
|
18138
|
-
}
|
|
18139
|
-
async gaAiReferralHistory(project, params) {
|
|
18140
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18141
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/ai-referral-history${qs}`);
|
|
18142
|
-
}
|
|
18143
|
-
async gaSocialReferralHistory(project, params) {
|
|
18144
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18145
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/social-referral-history${qs}`);
|
|
18146
|
-
}
|
|
18147
|
-
async gaSocialReferralTrend(project) {
|
|
18148
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/social-referral-trend`);
|
|
18149
|
-
}
|
|
18150
|
-
async gaAttributionTrend(project) {
|
|
18151
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/attribution-trend`);
|
|
18152
|
-
}
|
|
18153
|
-
async gaSessionHistory(project, params) {
|
|
18154
|
-
const qs = params ? "?" + new URLSearchParams(params).toString() : "";
|
|
18155
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/ga/session-history${qs}`);
|
|
18156
|
-
}
|
|
18157
|
-
async wordpressConnect(project, body) {
|
|
18158
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/connect`, body);
|
|
18159
|
-
}
|
|
18160
|
-
async wordpressDisconnect(project) {
|
|
18161
|
-
await this.request("DELETE", `/projects/${encodeURIComponent(project)}/wordpress/disconnect`);
|
|
18162
|
-
}
|
|
18163
|
-
async wordpressStatus(project) {
|
|
18164
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/status`);
|
|
18165
|
-
}
|
|
18166
|
-
async wordpressPages(project, env) {
|
|
18167
|
-
const qs = env ? `?env=${encodeURIComponent(env)}` : "";
|
|
18168
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/pages${qs}`);
|
|
18169
|
-
}
|
|
18170
|
-
async wordpressPage(project, slug, env) {
|
|
18171
|
-
const params = new URLSearchParams({ slug });
|
|
18172
|
-
if (env) params.set("env", env);
|
|
18173
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/page?${params.toString()}`);
|
|
18174
|
-
}
|
|
18175
|
-
async wordpressCreatePage(project, body) {
|
|
18176
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/pages`, body);
|
|
18177
|
-
}
|
|
18178
|
-
async wordpressUpdatePage(project, body) {
|
|
18179
|
-
return this.request("PUT", `/projects/${encodeURIComponent(project)}/wordpress/page`, body);
|
|
18180
|
-
}
|
|
18181
|
-
async wordpressSetMeta(project, body) {
|
|
18182
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/page/meta`, body);
|
|
18183
|
-
}
|
|
18184
|
-
async wordpressBulkSetMeta(project, body) {
|
|
18185
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/pages/meta/bulk`, body);
|
|
18186
|
-
}
|
|
18187
|
-
async wordpressSchema(project, slug, env) {
|
|
18188
|
-
const params = new URLSearchParams({ slug });
|
|
18189
|
-
if (env) params.set("env", env);
|
|
18190
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/schema?${params.toString()}`);
|
|
18191
|
-
}
|
|
18192
|
-
async wordpressSetSchema(project, body) {
|
|
18193
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/schema/manual`, body);
|
|
18194
|
-
}
|
|
18195
|
-
async wordpressSchemaDeploy(project, body) {
|
|
18196
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/schema/deploy`, body);
|
|
18197
|
-
}
|
|
18198
|
-
async wordpressSchemaStatus(project, env) {
|
|
18199
|
-
const params = new URLSearchParams();
|
|
18200
|
-
if (env) params.set("env", env);
|
|
18201
|
-
const qs = params.toString();
|
|
18202
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/schema/status${qs ? `?${qs}` : ""}`);
|
|
18203
|
-
}
|
|
18204
|
-
async wordpressOnboard(project, body) {
|
|
18205
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/onboard`, body);
|
|
18206
|
-
}
|
|
18207
|
-
async wordpressLlmsTxt(project, env) {
|
|
18208
|
-
const qs = env ? `?env=${encodeURIComponent(env)}` : "";
|
|
18209
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/llms-txt${qs}`);
|
|
18210
|
-
}
|
|
18211
|
-
async wordpressSetLlmsTxt(project, body) {
|
|
18212
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/llms-txt/manual`, body);
|
|
18213
|
-
}
|
|
18214
|
-
async wordpressAudit(project, env) {
|
|
18215
|
-
const qs = env ? `?env=${encodeURIComponent(env)}` : "";
|
|
18216
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/audit${qs}`);
|
|
18217
|
-
}
|
|
18218
|
-
async wordpressDiff(project, slug) {
|
|
18219
|
-
const params = new URLSearchParams({ slug });
|
|
18220
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/diff?${params.toString()}`);
|
|
18221
|
-
}
|
|
18222
|
-
async wordpressStagingStatus(project) {
|
|
18223
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/wordpress/staging/status`);
|
|
18224
|
-
}
|
|
18225
|
-
async wordpressStagingPush(project) {
|
|
18226
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/wordpress/staging/push`);
|
|
18227
|
-
}
|
|
18228
|
-
// ── Intelligence ──────────────────────────────────────────────────────
|
|
18229
|
-
async getInsights(project, opts) {
|
|
18230
|
-
const params = new URLSearchParams();
|
|
18231
|
-
if (opts?.dismissed) params.set("dismissed", "true");
|
|
18232
|
-
if (opts?.runId) params.set("runId", opts.runId);
|
|
18233
|
-
const qs = params.toString();
|
|
18234
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/insights${qs ? `?${qs}` : ""}`);
|
|
18235
|
-
}
|
|
18236
|
-
async dismissInsight(project, id) {
|
|
18237
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/insights/${encodeURIComponent(id)}/dismiss`);
|
|
18238
|
-
}
|
|
18239
|
-
async getHealth(project) {
|
|
18240
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/health/latest`);
|
|
18241
|
-
}
|
|
18242
|
-
async getHealthHistory(project, limit) {
|
|
18243
|
-
const qs = limit ? `?limit=${limit}` : "";
|
|
18244
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/health/history${qs}`);
|
|
18245
|
-
}
|
|
18246
|
-
// --- Backlinks ---------------------------------------------------------
|
|
18247
|
-
async backlinksStatus() {
|
|
18248
|
-
return this.request("GET", "/backlinks/status");
|
|
18249
|
-
}
|
|
18250
|
-
async backlinksInstall() {
|
|
18251
|
-
return this.request("POST", "/backlinks/install");
|
|
18252
|
-
}
|
|
18253
|
-
async backlinksTriggerSync(release) {
|
|
18254
|
-
return this.request("POST", "/backlinks/syncs", { release });
|
|
18255
|
-
}
|
|
18256
|
-
async backlinksLatestSync() {
|
|
18257
|
-
return this.request("GET", "/backlinks/syncs/latest");
|
|
18258
|
-
}
|
|
18259
|
-
async backlinksListSyncs() {
|
|
18260
|
-
return this.request("GET", "/backlinks/syncs");
|
|
18261
|
-
}
|
|
18262
|
-
async backlinksCachedReleases() {
|
|
18263
|
-
return this.request("GET", "/backlinks/releases");
|
|
18264
|
-
}
|
|
18265
|
-
async backlinksPruneCache(release) {
|
|
18266
|
-
return this.request("DELETE", `/backlinks/cache/${encodeURIComponent(release)}`);
|
|
18267
|
-
}
|
|
18268
|
-
async backlinksExtract(project, release) {
|
|
18269
|
-
return this.request("POST", `/projects/${encodeURIComponent(project)}/backlinks/extract`, release ? { release } : {});
|
|
18270
|
-
}
|
|
18271
|
-
async backlinksSummary(project, release) {
|
|
18272
|
-
const qs = release ? `?release=${encodeURIComponent(release)}` : "";
|
|
18273
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/backlinks/summary${qs}`);
|
|
18274
|
-
}
|
|
18275
|
-
async backlinksDomains(project, opts = {}) {
|
|
18276
|
-
const qs = new URLSearchParams();
|
|
18277
|
-
if (opts.limit !== void 0) qs.set("limit", String(opts.limit));
|
|
18278
|
-
if (opts.offset !== void 0) qs.set("offset", String(opts.offset));
|
|
18279
|
-
if (opts.release) qs.set("release", opts.release);
|
|
18280
|
-
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
18281
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/backlinks/domains${suffix}`);
|
|
18282
|
-
}
|
|
18283
|
-
async backlinksHistory(project) {
|
|
18284
|
-
return this.request("GET", `/projects/${encodeURIComponent(project)}/backlinks/history`);
|
|
18285
|
-
}
|
|
18286
|
-
};
|
|
18287
|
-
|
|
18288
16349
|
// src/snapshot-service.ts
|
|
18289
16350
|
import { runAeoAudit } from "@ainyc/aeo-audit";
|
|
18290
16351
|
|
|
@@ -18307,13 +16368,13 @@ function extractHostname(domain) {
|
|
|
18307
16368
|
function fetchWithPinnedAddress(target) {
|
|
18308
16369
|
return new Promise((resolve) => {
|
|
18309
16370
|
const port = target.url.port ? Number(target.url.port) : 443;
|
|
18310
|
-
const
|
|
16371
|
+
const path15 = target.url.pathname + target.url.search;
|
|
18311
16372
|
const req = https2.request(
|
|
18312
16373
|
{
|
|
18313
16374
|
hostname: target.address,
|
|
18314
16375
|
family: target.family,
|
|
18315
16376
|
port,
|
|
18316
|
-
path:
|
|
16377
|
+
path: path15,
|
|
18317
16378
|
method: "GET",
|
|
18318
16379
|
timeout: FETCH_TIMEOUT_MS,
|
|
18319
16380
|
servername: target.url.hostname,
|
|
@@ -19206,8 +17267,8 @@ async function createServer(opts) {
|
|
|
19206
17267
|
);
|
|
19207
17268
|
jobRunner.onRunCompleted = (runId, projectId) => runCoordinator.onRunCompleted(runId, projectId);
|
|
19208
17269
|
const snapshotService = new SnapshotService(registry);
|
|
19209
|
-
const orphanedOpenClawDir =
|
|
19210
|
-
if (
|
|
17270
|
+
const orphanedOpenClawDir = path14.join(os5.homedir(), ".openclaw-aero");
|
|
17271
|
+
if (fs12.existsSync(orphanedOpenClawDir)) {
|
|
19211
17272
|
app.log.warn(
|
|
19212
17273
|
{ path: orphanedOpenClawDir },
|
|
19213
17274
|
"OpenClaw gateway is no longer used. Remove ~/.openclaw-aero/ manually to reclaim the directory."
|
|
@@ -19801,10 +17862,10 @@ async function createServer(opts) {
|
|
|
19801
17862
|
return snapshotService.createReport(input);
|
|
19802
17863
|
}
|
|
19803
17864
|
});
|
|
19804
|
-
const dirname =
|
|
19805
|
-
const assetsDir =
|
|
19806
|
-
if (
|
|
19807
|
-
const indexPath =
|
|
17865
|
+
const dirname = path14.dirname(fileURLToPath2(import.meta.url));
|
|
17866
|
+
const assetsDir = path14.join(dirname, "..", "assets");
|
|
17867
|
+
if (fs12.existsSync(assetsDir)) {
|
|
17868
|
+
const indexPath = path14.join(assetsDir, "index.html");
|
|
19808
17869
|
const injectConfig = (html) => {
|
|
19809
17870
|
const clientConfig = {};
|
|
19810
17871
|
if (basePath) clientConfig.basePath = basePath;
|
|
@@ -19822,8 +17883,8 @@ async function createServer(opts) {
|
|
|
19822
17883
|
index: false
|
|
19823
17884
|
});
|
|
19824
17885
|
const serveIndex = (_request, reply) => {
|
|
19825
|
-
if (
|
|
19826
|
-
const html =
|
|
17886
|
+
if (fs12.existsSync(indexPath)) {
|
|
17887
|
+
const html = fs12.readFileSync(indexPath, "utf-8");
|
|
19827
17888
|
return reply.type("text/html").send(injectConfig(html));
|
|
19828
17889
|
}
|
|
19829
17890
|
return reply.status(404).send({ error: "Dashboard not built" });
|
|
@@ -19843,8 +17904,8 @@ async function createServer(opts) {
|
|
|
19843
17904
|
if (basePath && !url.startsWith(basePath)) {
|
|
19844
17905
|
return reply.status(404).send({ error: "Not found", path: request.url });
|
|
19845
17906
|
}
|
|
19846
|
-
if (
|
|
19847
|
-
const html =
|
|
17907
|
+
if (fs12.existsSync(indexPath)) {
|
|
17908
|
+
const html = fs12.readFileSync(indexPath, "utf-8");
|
|
19848
17909
|
return reply.type("text/html").send(injectConfig(html));
|
|
19849
17910
|
}
|
|
19850
17911
|
return reply.status(404).send({ error: "Not found" });
|
|
@@ -19913,31 +17974,11 @@ function parseKeywordResponse(raw, count) {
|
|
|
19913
17974
|
}
|
|
19914
17975
|
|
|
19915
17976
|
export {
|
|
19916
|
-
getConfigDir,
|
|
19917
|
-
getConfigPath,
|
|
19918
|
-
loadConfig,
|
|
19919
|
-
saveConfig,
|
|
19920
|
-
saveConfigPatch,
|
|
19921
|
-
configExists,
|
|
19922
17977
|
isTelemetryEnabled,
|
|
19923
17978
|
getOrCreateAnonymousId,
|
|
19924
17979
|
isFirstRun,
|
|
19925
17980
|
showFirstRunNotice,
|
|
19926
17981
|
trackEvent,
|
|
19927
|
-
EXIT_SYSTEM_ERROR,
|
|
19928
|
-
CliError,
|
|
19929
|
-
usageError,
|
|
19930
|
-
isEndpointMissing,
|
|
19931
|
-
printCliError,
|
|
19932
|
-
providerQuotaPolicySchema,
|
|
19933
|
-
ProviderNames,
|
|
19934
|
-
resolveProviderInput,
|
|
19935
|
-
notificationEventSchema,
|
|
19936
|
-
effectiveDomains,
|
|
19937
|
-
RunStatuses,
|
|
19938
|
-
RunKinds,
|
|
19939
|
-
determineAnswerMentioned,
|
|
19940
|
-
CcReleaseSyncStatuses,
|
|
19941
17982
|
reparseStoredResult2 as reparseStoredResult,
|
|
19942
17983
|
reparseStoredResult3 as reparseStoredResult2,
|
|
19943
17984
|
reparseStoredResult as reparseStoredResult3,
|
|
@@ -19945,7 +17986,6 @@ export {
|
|
|
19945
17986
|
determineCitationState,
|
|
19946
17987
|
computeCompetitorOverlap,
|
|
19947
17988
|
extractRecommendedCompetitors,
|
|
19948
|
-
createApiClient,
|
|
19949
17989
|
setGoogleAuthConfig,
|
|
19950
17990
|
formatAuditFactorScore,
|
|
19951
17991
|
listAgentProviders,
|