@ainyc/canonry 1.37.0 → 1.38.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-BZX6FEZ4.css → index-CM92zXYn.css} +1 -1
- package/assets/assets/{index-DR4zYsnw.js → index-Du9ZvTq9.js} +55 -55
- package/assets/index.html +2 -2
- package/dist/{chunk-5MOWJJND.js → chunk-SAVCFB5B.js} +398 -213
- package/dist/cli.js +54 -51
- package/dist/index.js +1 -1
- package/package.json +8 -8
|
@@ -1878,6 +1878,12 @@ var MIGRATIONS = [
|
|
|
1878
1878
|
`DROP INDEX IF EXISTS idx_ga_ai_ref_unique`,
|
|
1879
1879
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_ga_ai_ref_unique_v2 ON ga_ai_referrals(project_id, date, source, medium, source_dimension)`
|
|
1880
1880
|
];
|
|
1881
|
+
function isDuplicateColumnError(err) {
|
|
1882
|
+
if (!(err instanceof Error)) return false;
|
|
1883
|
+
if (err.message.includes("duplicate column name")) return true;
|
|
1884
|
+
if (err.cause instanceof Error && err.cause.message.includes("duplicate column name")) return true;
|
|
1885
|
+
return false;
|
|
1886
|
+
}
|
|
1881
1887
|
function migrate(db) {
|
|
1882
1888
|
const statements = MIGRATION_SQL.split(";").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
1883
1889
|
for (const statement of statements) {
|
|
@@ -1886,7 +1892,9 @@ function migrate(db) {
|
|
|
1886
1892
|
for (const migration of MIGRATIONS) {
|
|
1887
1893
|
try {
|
|
1888
1894
|
db.run(sql.raw(migration));
|
|
1889
|
-
} catch {
|
|
1895
|
+
} catch (err) {
|
|
1896
|
+
if (isDuplicateColumnError(err)) continue;
|
|
1897
|
+
throw err;
|
|
1890
1898
|
}
|
|
1891
1899
|
}
|
|
1892
1900
|
}
|
|
@@ -10386,20 +10394,33 @@ async function apiRoutes(app, opts) {
|
|
|
10386
10394
|
|
|
10387
10395
|
// ../provider-gemini/src/normalize.ts
|
|
10388
10396
|
import { GoogleGenAI } from "@google/genai";
|
|
10397
|
+
|
|
10398
|
+
// ../provider-gemini/src/utils.ts
|
|
10399
|
+
async function withRetry(fn, options = {}) {
|
|
10400
|
+
const { maxRetries = 3, initialDelay = 1e3 } = options;
|
|
10401
|
+
let lastError;
|
|
10402
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
10403
|
+
try {
|
|
10404
|
+
return await fn();
|
|
10405
|
+
} catch (err) {
|
|
10406
|
+
lastError = err;
|
|
10407
|
+
if (attempt < maxRetries) {
|
|
10408
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
10409
|
+
console.warn(`[provider] Attempt ${attempt + 1} failed, retrying in ${delay}ms...`, err);
|
|
10410
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
10411
|
+
}
|
|
10412
|
+
}
|
|
10413
|
+
}
|
|
10414
|
+
throw lastError;
|
|
10415
|
+
}
|
|
10416
|
+
|
|
10417
|
+
// ../provider-gemini/src/normalize.ts
|
|
10389
10418
|
var DEFAULT_MODEL = "gemini-3-flash";
|
|
10390
|
-
var VALIDATION_PATTERN = /^gemini-/;
|
|
10391
10419
|
function isVertexConfig(config) {
|
|
10392
10420
|
return !!config.vertexProject;
|
|
10393
10421
|
}
|
|
10394
10422
|
function resolveModel(config) {
|
|
10395
|
-
|
|
10396
|
-
if (!m) return DEFAULT_MODEL;
|
|
10397
|
-
if (VALIDATION_PATTERN.test(m)) return m;
|
|
10398
|
-
const backend = isVertexConfig(config) ? "Vertex AI" : "AI Studio";
|
|
10399
|
-
console.warn(
|
|
10400
|
-
`[provider-gemini] Invalid model name "${m}" \u2014 this provider uses the Gemini ${backend} API which only accepts "gemini-*" model names. Falling back to ${DEFAULT_MODEL}.`
|
|
10401
|
-
);
|
|
10402
|
-
return DEFAULT_MODEL;
|
|
10423
|
+
return config.model || DEFAULT_MODEL;
|
|
10403
10424
|
}
|
|
10404
10425
|
function createClient2(config) {
|
|
10405
10426
|
if (isVertexConfig(config)) {
|
|
@@ -10413,6 +10434,9 @@ function createClient2(config) {
|
|
|
10413
10434
|
return new GoogleGenAI({ apiKey: config.apiKey });
|
|
10414
10435
|
}
|
|
10415
10436
|
function validateConfig(config) {
|
|
10437
|
+
if ("vertexProject" in config && config.vertexProject !== void 0 && config.vertexProject.trim().length === 0) {
|
|
10438
|
+
return { ok: false, provider: "gemini", message: "missing Vertex AI project ID" };
|
|
10439
|
+
}
|
|
10416
10440
|
if (isVertexConfig(config)) {
|
|
10417
10441
|
const model2 = resolveModel(config);
|
|
10418
10442
|
return {
|
|
@@ -10426,11 +10450,10 @@ function validateConfig(config) {
|
|
|
10426
10450
|
return { ok: false, provider: "gemini", message: "missing api key" };
|
|
10427
10451
|
}
|
|
10428
10452
|
const model = resolveModel(config);
|
|
10429
|
-
const warning = config.model && !VALIDATION_PATTERN.test(config.model) ? ` (invalid model "${config.model}" replaced with default)` : "";
|
|
10430
10453
|
return {
|
|
10431
10454
|
ok: true,
|
|
10432
10455
|
provider: "gemini",
|
|
10433
|
-
message:
|
|
10456
|
+
message: "config valid",
|
|
10434
10457
|
model
|
|
10435
10458
|
};
|
|
10436
10459
|
}
|
|
@@ -10440,10 +10463,12 @@ async function healthcheck(config) {
|
|
|
10440
10463
|
try {
|
|
10441
10464
|
const model = resolveModel(config);
|
|
10442
10465
|
const client = createClient2(config);
|
|
10443
|
-
const result = await
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
|
|
10466
|
+
const result = await withRetry(
|
|
10467
|
+
() => client.models.generateContent({
|
|
10468
|
+
model,
|
|
10469
|
+
contents: 'Say "ok"'
|
|
10470
|
+
})
|
|
10471
|
+
);
|
|
10447
10472
|
const text2 = result.text ?? "";
|
|
10448
10473
|
const backend = isVertexConfig(config) ? "vertex ai" : "api key";
|
|
10449
10474
|
return {
|
|
@@ -10465,22 +10490,29 @@ async function executeTrackedQuery(input) {
|
|
|
10465
10490
|
const model = resolveModel(input.config);
|
|
10466
10491
|
const prompt = buildPrompt(input.keyword, input.location);
|
|
10467
10492
|
const client = createClient2(input.config);
|
|
10468
|
-
|
|
10469
|
-
|
|
10470
|
-
|
|
10471
|
-
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
|
|
10475
|
-
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
|
|
10493
|
+
try {
|
|
10494
|
+
const result = await withRetry(
|
|
10495
|
+
() => client.models.generateContent({
|
|
10496
|
+
model,
|
|
10497
|
+
contents: prompt,
|
|
10498
|
+
config: {
|
|
10499
|
+
tools: [{ googleSearch: {} }]
|
|
10500
|
+
}
|
|
10501
|
+
})
|
|
10502
|
+
);
|
|
10503
|
+
const groundingSources = extractGroundingMetadata(result);
|
|
10504
|
+
const searchQueries = extractSearchQueries(result);
|
|
10505
|
+
return {
|
|
10506
|
+
provider: "gemini",
|
|
10507
|
+
rawResponse: responseToRecord(result),
|
|
10508
|
+
model,
|
|
10509
|
+
groundingSources,
|
|
10510
|
+
searchQueries
|
|
10511
|
+
};
|
|
10512
|
+
} catch (err) {
|
|
10513
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10514
|
+
throw new Error(`[provider-gemini] ${msg}`);
|
|
10515
|
+
}
|
|
10484
10516
|
}
|
|
10485
10517
|
function normalizeResult(raw) {
|
|
10486
10518
|
const answerText = extractAnswerText(raw.rawResponse);
|
|
@@ -10582,10 +10614,12 @@ function extractDomainFromUri(uri) {
|
|
|
10582
10614
|
async function generateText(prompt, config) {
|
|
10583
10615
|
const model = resolveModel(config);
|
|
10584
10616
|
const client = createClient2(config);
|
|
10585
|
-
const result = await
|
|
10586
|
-
|
|
10587
|
-
|
|
10588
|
-
|
|
10617
|
+
const result = await withRetry(
|
|
10618
|
+
() => client.models.generateContent({
|
|
10619
|
+
model,
|
|
10620
|
+
contents: prompt
|
|
10621
|
+
})
|
|
10622
|
+
);
|
|
10589
10623
|
return result.text ?? "";
|
|
10590
10624
|
}
|
|
10591
10625
|
function responseToRecord(response) {
|
|
@@ -10623,12 +10657,14 @@ var geminiAdapter = {
|
|
|
10623
10657
|
displayName: "Gemini",
|
|
10624
10658
|
mode: "api",
|
|
10625
10659
|
keyUrl: "https://aistudio.google.com/apikey",
|
|
10660
|
+
// Upstream model list: https://ai.google.dev/gemini-api/docs/models
|
|
10626
10661
|
modelRegistry: {
|
|
10627
10662
|
defaultModel: "gemini-3-flash",
|
|
10628
|
-
validationPattern:
|
|
10629
|
-
validationHint:
|
|
10663
|
+
validationPattern: /./,
|
|
10664
|
+
validationHint: "any valid Google model name (e.g. gemini-3-flash, learnlm-1.5-pro-experimental)",
|
|
10630
10665
|
knownModels: [
|
|
10631
10666
|
{ id: "gemini-3.1-pro-preview", displayName: "Gemini 3.1 Pro (Preview)", tier: "flagship" },
|
|
10667
|
+
{ id: "gemini-3-flash", displayName: "Gemini 3 Flash", tier: "standard" },
|
|
10632
10668
|
{ id: "gemini-3-flash-preview", displayName: "Gemini 3 Flash (Preview)", tier: "standard" },
|
|
10633
10669
|
{ id: "gemini-3.1-flash-lite-preview", displayName: "Gemini 3.1 Flash-Lite (Preview)", tier: "economy" },
|
|
10634
10670
|
{ id: "gemini-2.5-flash", displayName: "Gemini 2.5 Flash", tier: "standard" }
|
|
@@ -10692,6 +10728,27 @@ var geminiAdapter = {
|
|
|
10692
10728
|
|
|
10693
10729
|
// ../provider-openai/src/normalize.ts
|
|
10694
10730
|
import OpenAI from "openai";
|
|
10731
|
+
|
|
10732
|
+
// ../provider-openai/src/utils.ts
|
|
10733
|
+
async function withRetry2(fn, options = {}) {
|
|
10734
|
+
const { maxRetries = 3, initialDelay = 1e3 } = options;
|
|
10735
|
+
let lastError;
|
|
10736
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
10737
|
+
try {
|
|
10738
|
+
return await fn();
|
|
10739
|
+
} catch (err) {
|
|
10740
|
+
lastError = err;
|
|
10741
|
+
if (attempt < maxRetries) {
|
|
10742
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
10743
|
+
console.warn(`[provider] Attempt ${attempt + 1} failed, retrying in ${delay}ms...`, err);
|
|
10744
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
10745
|
+
}
|
|
10746
|
+
}
|
|
10747
|
+
}
|
|
10748
|
+
throw lastError;
|
|
10749
|
+
}
|
|
10750
|
+
|
|
10751
|
+
// ../provider-openai/src/normalize.ts
|
|
10695
10752
|
var DEFAULT_MODEL2 = "gpt-5.4";
|
|
10696
10753
|
function validateConfig2(config) {
|
|
10697
10754
|
if (!config.apiKey || config.apiKey.length === 0) {
|
|
@@ -10709,10 +10766,12 @@ async function healthcheck2(config) {
|
|
|
10709
10766
|
if (!validation.ok) return validation;
|
|
10710
10767
|
try {
|
|
10711
10768
|
const client = new OpenAI({ apiKey: config.apiKey });
|
|
10712
|
-
const response = await
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10769
|
+
const response = await withRetry2(
|
|
10770
|
+
() => client.responses.create({
|
|
10771
|
+
model: config.model ?? DEFAULT_MODEL2,
|
|
10772
|
+
input: 'Say "ok"'
|
|
10773
|
+
})
|
|
10774
|
+
);
|
|
10716
10775
|
const text2 = extractResponseText(response);
|
|
10717
10776
|
return {
|
|
10718
10777
|
ok: text2.length > 0,
|
|
@@ -10742,21 +10801,28 @@ async function executeTrackedQuery2(input) {
|
|
|
10742
10801
|
...input.location.timezone ? { timezone: input.location.timezone } : {}
|
|
10743
10802
|
};
|
|
10744
10803
|
}
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10804
|
+
try {
|
|
10805
|
+
const response = await withRetry2(
|
|
10806
|
+
() => client.responses.create({
|
|
10807
|
+
model,
|
|
10808
|
+
tools: [webSearchTool],
|
|
10809
|
+
tool_choice: "required",
|
|
10810
|
+
input: buildPrompt2(input.keyword)
|
|
10811
|
+
})
|
|
10812
|
+
);
|
|
10813
|
+
const groundingSources = extractGroundingSources(response);
|
|
10814
|
+
const searchQueries = extractSearchQueries2(response);
|
|
10815
|
+
return {
|
|
10816
|
+
provider: "openai",
|
|
10817
|
+
rawResponse: responseToRecord2(response),
|
|
10818
|
+
model,
|
|
10819
|
+
groundingSources,
|
|
10820
|
+
searchQueries
|
|
10821
|
+
};
|
|
10822
|
+
} catch (err) {
|
|
10823
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10824
|
+
throw new Error(`[provider-openai] ${msg}`);
|
|
10825
|
+
}
|
|
10760
10826
|
}
|
|
10761
10827
|
function normalizeResult2(raw) {
|
|
10762
10828
|
const answerText = extractAnswerTextFromRaw(raw.rawResponse);
|
|
@@ -10791,13 +10857,15 @@ function extractResponseText(response) {
|
|
|
10791
10857
|
}
|
|
10792
10858
|
function extractGroundingSources(response) {
|
|
10793
10859
|
const sources = [];
|
|
10860
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10794
10861
|
try {
|
|
10795
10862
|
for (const item of response.output) {
|
|
10796
10863
|
if (item.type === "message") {
|
|
10797
10864
|
for (const content of item.content) {
|
|
10798
10865
|
if (content.type === "output_text" && content.annotations) {
|
|
10799
10866
|
for (const annotation of content.annotations) {
|
|
10800
|
-
if (annotation.type === "url_citation") {
|
|
10867
|
+
if (annotation.type === "url_citation" && !seen.has(annotation.url)) {
|
|
10868
|
+
seen.add(annotation.url);
|
|
10801
10869
|
sources.push({
|
|
10802
10870
|
uri: annotation.url,
|
|
10803
10871
|
title: annotation.title ?? ""
|
|
@@ -10817,7 +10885,10 @@ function extractSearchQueries2(response) {
|
|
|
10817
10885
|
try {
|
|
10818
10886
|
for (const item of response.output) {
|
|
10819
10887
|
if (item.type === "web_search_call" && "query" in item) {
|
|
10820
|
-
|
|
10888
|
+
const query = item.query;
|
|
10889
|
+
if (typeof query === "string" && query.length > 0) {
|
|
10890
|
+
queries.push(query);
|
|
10891
|
+
}
|
|
10821
10892
|
}
|
|
10822
10893
|
}
|
|
10823
10894
|
} catch {
|
|
@@ -10862,10 +10933,12 @@ function extractDomainFromUri2(uri) {
|
|
|
10862
10933
|
async function generateText2(prompt, config) {
|
|
10863
10934
|
const model = config.model ?? DEFAULT_MODEL2;
|
|
10864
10935
|
const client = new OpenAI({ apiKey: config.apiKey });
|
|
10865
|
-
const response = await
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10936
|
+
const response = await withRetry2(
|
|
10937
|
+
() => client.responses.create({
|
|
10938
|
+
model,
|
|
10939
|
+
input: prompt
|
|
10940
|
+
})
|
|
10941
|
+
);
|
|
10869
10942
|
return extractResponseText(response);
|
|
10870
10943
|
}
|
|
10871
10944
|
function responseToRecord2(response) {
|
|
@@ -10889,10 +10962,11 @@ var openaiAdapter = {
|
|
|
10889
10962
|
displayName: "OpenAI",
|
|
10890
10963
|
mode: "api",
|
|
10891
10964
|
keyUrl: "https://platform.openai.com/api-keys",
|
|
10965
|
+
// Upstream model list: https://platform.openai.com/docs/models
|
|
10892
10966
|
modelRegistry: {
|
|
10893
10967
|
defaultModel: "gpt-5.4",
|
|
10894
|
-
validationPattern:
|
|
10895
|
-
validationHint: "
|
|
10968
|
+
validationPattern: /./,
|
|
10969
|
+
validationHint: "any valid OpenAI model name (e.g. gpt-5.4, o3, chatgpt-4o-latest)",
|
|
10896
10970
|
knownModels: [
|
|
10897
10971
|
{ id: "gpt-5.4", displayName: "GPT-5.4", tier: "flagship" },
|
|
10898
10972
|
{ id: "gpt-5.4-pro", displayName: "GPT-5.4 Pro", tier: "flagship" },
|
|
@@ -10960,46 +11034,82 @@ var openaiAdapter = {
|
|
|
10960
11034
|
|
|
10961
11035
|
// ../provider-claude/src/normalize.ts
|
|
10962
11036
|
import Anthropic from "@anthropic-ai/sdk";
|
|
11037
|
+
|
|
11038
|
+
// ../provider-claude/src/utils.ts
|
|
11039
|
+
async function withRetry3(fn, options = {}) {
|
|
11040
|
+
const { maxRetries = 3, initialDelay = 1e3 } = options;
|
|
11041
|
+
let lastError;
|
|
11042
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
11043
|
+
try {
|
|
11044
|
+
return await fn();
|
|
11045
|
+
} catch (err) {
|
|
11046
|
+
lastError = err;
|
|
11047
|
+
if (attempt < maxRetries) {
|
|
11048
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
11049
|
+
console.warn(`[provider] Attempt ${attempt + 1} failed, retrying in ${delay}ms...`, err);
|
|
11050
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
11051
|
+
}
|
|
11052
|
+
}
|
|
11053
|
+
}
|
|
11054
|
+
throw lastError;
|
|
11055
|
+
}
|
|
11056
|
+
|
|
11057
|
+
// ../provider-claude/src/normalize.ts
|
|
10963
11058
|
var DEFAULT_MODEL3 = "claude-sonnet-4-6";
|
|
11059
|
+
var VALIDATION_PATTERN = /^claude-/;
|
|
11060
|
+
function resolveModel2(config) {
|
|
11061
|
+
const m = config.model;
|
|
11062
|
+
if (!m) return DEFAULT_MODEL3;
|
|
11063
|
+
if (VALIDATION_PATTERN.test(m)) return m;
|
|
11064
|
+
console.warn(
|
|
11065
|
+
`[provider-claude] Invalid model name "${m}" \u2014 this provider uses the Anthropic API which only accepts "claude-*" model names. Falling back to ${DEFAULT_MODEL3}.`
|
|
11066
|
+
);
|
|
11067
|
+
return DEFAULT_MODEL3;
|
|
11068
|
+
}
|
|
10964
11069
|
function validateConfig3(config) {
|
|
10965
11070
|
if (!config.apiKey || config.apiKey.length === 0) {
|
|
10966
11071
|
return { ok: false, provider: "claude", message: "missing api key" };
|
|
10967
11072
|
}
|
|
11073
|
+
const model = resolveModel2(config);
|
|
11074
|
+
const warning = config.model && !VALIDATION_PATTERN.test(config.model) ? ` (invalid model "${config.model}" replaced with default)` : "";
|
|
10968
11075
|
return {
|
|
10969
11076
|
ok: true,
|
|
10970
11077
|
provider: "claude",
|
|
10971
|
-
message:
|
|
10972
|
-
model
|
|
11078
|
+
message: `config valid${warning}`,
|
|
11079
|
+
model
|
|
10973
11080
|
};
|
|
10974
11081
|
}
|
|
10975
11082
|
async function healthcheck3(config) {
|
|
10976
11083
|
const validation = validateConfig3(config);
|
|
10977
11084
|
if (!validation.ok) return validation;
|
|
10978
11085
|
try {
|
|
11086
|
+
const model = resolveModel2(config);
|
|
10979
11087
|
const client = new Anthropic({ apiKey: config.apiKey });
|
|
10980
|
-
const response = await
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
11088
|
+
const response = await withRetry3(
|
|
11089
|
+
() => client.messages.create({
|
|
11090
|
+
model,
|
|
11091
|
+
max_tokens: 32,
|
|
11092
|
+
messages: [{ role: "user", content: 'Say "ok"' }]
|
|
11093
|
+
})
|
|
11094
|
+
);
|
|
10985
11095
|
const text2 = extractTextFromResponse(response);
|
|
10986
11096
|
return {
|
|
10987
11097
|
ok: text2.length > 0,
|
|
10988
11098
|
provider: "claude",
|
|
10989
11099
|
message: text2.length > 0 ? "claude api key verified" : "empty response from claude",
|
|
10990
|
-
model
|
|
11100
|
+
model
|
|
10991
11101
|
};
|
|
10992
11102
|
} catch (err) {
|
|
10993
11103
|
return {
|
|
10994
11104
|
ok: false,
|
|
10995
11105
|
provider: "claude",
|
|
10996
11106
|
message: err instanceof Error ? err.message : String(err),
|
|
10997
|
-
model: config
|
|
11107
|
+
model: resolveModel2(config)
|
|
10998
11108
|
};
|
|
10999
11109
|
}
|
|
11000
11110
|
}
|
|
11001
11111
|
async function executeTrackedQuery3(input) {
|
|
11002
|
-
const model = input.config
|
|
11112
|
+
const model = resolveModel2(input.config);
|
|
11003
11113
|
const client = new Anthropic({ apiKey: input.config.apiKey });
|
|
11004
11114
|
const webSearchTool = {
|
|
11005
11115
|
type: "web_search_20250305",
|
|
@@ -11015,21 +11125,28 @@ async function executeTrackedQuery3(input) {
|
|
|
11015
11125
|
...input.location.timezone ? { timezone: input.location.timezone } : {}
|
|
11016
11126
|
};
|
|
11017
11127
|
}
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11128
|
+
try {
|
|
11129
|
+
const response = await withRetry3(
|
|
11130
|
+
() => client.messages.create({
|
|
11131
|
+
model,
|
|
11132
|
+
max_tokens: 4096,
|
|
11133
|
+
tools: [webSearchTool],
|
|
11134
|
+
messages: [{ role: "user", content: input.keyword }]
|
|
11135
|
+
})
|
|
11136
|
+
);
|
|
11137
|
+
const groundingSources = extractGroundingSources2(response);
|
|
11138
|
+
const searchQueries = extractSearchQueries3(response);
|
|
11139
|
+
return {
|
|
11140
|
+
provider: "claude",
|
|
11141
|
+
rawResponse: responseToRecord3(response),
|
|
11142
|
+
model,
|
|
11143
|
+
groundingSources,
|
|
11144
|
+
searchQueries
|
|
11145
|
+
};
|
|
11146
|
+
} catch (err) {
|
|
11147
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11148
|
+
throw new Error(`[provider-claude] ${msg}`);
|
|
11149
|
+
}
|
|
11033
11150
|
}
|
|
11034
11151
|
function normalizeResult3(raw) {
|
|
11035
11152
|
const answerText = extractAnswerTextFromRaw2(raw.rawResponse);
|
|
@@ -11121,13 +11238,15 @@ function extractDomainFromUri3(uri) {
|
|
|
11121
11238
|
}
|
|
11122
11239
|
}
|
|
11123
11240
|
async function generateText3(prompt, config) {
|
|
11124
|
-
const model = config
|
|
11241
|
+
const model = resolveModel2(config);
|
|
11125
11242
|
const client = new Anthropic({ apiKey: config.apiKey });
|
|
11126
|
-
const response = await
|
|
11127
|
-
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11243
|
+
const response = await withRetry3(
|
|
11244
|
+
() => client.messages.create({
|
|
11245
|
+
model,
|
|
11246
|
+
max_tokens: 2048,
|
|
11247
|
+
messages: [{ role: "user", content: prompt }]
|
|
11248
|
+
})
|
|
11249
|
+
);
|
|
11131
11250
|
return extractTextFromResponse(response);
|
|
11132
11251
|
}
|
|
11133
11252
|
function responseToRecord3(response) {
|
|
@@ -11151,6 +11270,7 @@ var claudeAdapter = {
|
|
|
11151
11270
|
displayName: "Claude",
|
|
11152
11271
|
mode: "api",
|
|
11153
11272
|
keyUrl: "https://platform.claude.com/settings/keys",
|
|
11273
|
+
// Upstream model list: https://platform.claude.com/docs/en/about-claude/models/overview
|
|
11154
11274
|
modelRegistry: {
|
|
11155
11275
|
defaultModel: "claude-sonnet-4-6",
|
|
11156
11276
|
validationPattern: /^claude-/,
|
|
@@ -11219,6 +11339,27 @@ var claudeAdapter = {
|
|
|
11219
11339
|
|
|
11220
11340
|
// ../provider-local/src/normalize.ts
|
|
11221
11341
|
import OpenAI2 from "openai";
|
|
11342
|
+
|
|
11343
|
+
// ../provider-local/src/utils.ts
|
|
11344
|
+
async function withRetry4(fn, options = {}) {
|
|
11345
|
+
const { maxRetries = 3, initialDelay = 1e3 } = options;
|
|
11346
|
+
let lastError;
|
|
11347
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
11348
|
+
try {
|
|
11349
|
+
return await fn();
|
|
11350
|
+
} catch (err) {
|
|
11351
|
+
lastError = err;
|
|
11352
|
+
if (attempt < maxRetries) {
|
|
11353
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
11354
|
+
console.warn(`[provider] Attempt ${attempt + 1} failed, retrying in ${delay}ms...`, err);
|
|
11355
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
11356
|
+
}
|
|
11357
|
+
}
|
|
11358
|
+
}
|
|
11359
|
+
throw lastError;
|
|
11360
|
+
}
|
|
11361
|
+
|
|
11362
|
+
// ../provider-local/src/normalize.ts
|
|
11222
11363
|
var DEFAULT_MODEL4 = "llama3";
|
|
11223
11364
|
function validateConfig4(config) {
|
|
11224
11365
|
if (!config.baseUrl || config.baseUrl.length === 0) {
|
|
@@ -11239,16 +11380,19 @@ async function healthcheck4(config) {
|
|
|
11239
11380
|
baseURL: config.baseUrl,
|
|
11240
11381
|
apiKey: config.apiKey || "not-needed"
|
|
11241
11382
|
});
|
|
11242
|
-
const models = await
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11383
|
+
const models = await withRetry4(async () => {
|
|
11384
|
+
const list = await client.models.list();
|
|
11385
|
+
const items = [];
|
|
11386
|
+
for await (const m of list) {
|
|
11387
|
+
items.push(m.id);
|
|
11388
|
+
if (items.length >= 5) break;
|
|
11389
|
+
}
|
|
11390
|
+
return items;
|
|
11391
|
+
});
|
|
11248
11392
|
return {
|
|
11249
11393
|
ok: true,
|
|
11250
11394
|
provider: "local",
|
|
11251
|
-
message: `connected, ${
|
|
11395
|
+
message: `connected, ${models.length} model(s) available`,
|
|
11252
11396
|
model: config.model ?? DEFAULT_MODEL4
|
|
11253
11397
|
};
|
|
11254
11398
|
} catch (err) {
|
|
@@ -11266,26 +11410,33 @@ async function executeTrackedQuery4(input) {
|
|
|
11266
11410
|
baseURL: input.config.baseUrl,
|
|
11267
11411
|
apiKey: input.config.apiKey || "not-needed"
|
|
11268
11412
|
});
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11413
|
+
try {
|
|
11414
|
+
const response = await withRetry4(
|
|
11415
|
+
() => client.chat.completions.create({
|
|
11416
|
+
model,
|
|
11417
|
+
messages: [
|
|
11418
|
+
{
|
|
11419
|
+
role: "system",
|
|
11420
|
+
content: "You are a helpful assistant. Provide comprehensive, factual answers. When mentioning websites or services, include their domain names."
|
|
11421
|
+
},
|
|
11422
|
+
{
|
|
11423
|
+
role: "user",
|
|
11424
|
+
content: buildPrompt3(input.keyword, input.location)
|
|
11425
|
+
}
|
|
11426
|
+
]
|
|
11427
|
+
})
|
|
11428
|
+
);
|
|
11429
|
+
return {
|
|
11430
|
+
provider: "local",
|
|
11431
|
+
rawResponse: responseToRecord4(response),
|
|
11432
|
+
model,
|
|
11433
|
+
groundingSources: [],
|
|
11434
|
+
searchQueries: []
|
|
11435
|
+
};
|
|
11436
|
+
} catch (err) {
|
|
11437
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11438
|
+
throw new Error(`[provider-local] ${msg}`);
|
|
11439
|
+
}
|
|
11289
11440
|
}
|
|
11290
11441
|
function normalizeResult4(raw) {
|
|
11291
11442
|
const answerText = extractAnswerText2(raw.rawResponse);
|
|
@@ -11317,10 +11468,12 @@ async function generateText4(prompt, config) {
|
|
|
11317
11468
|
baseURL: config.baseUrl,
|
|
11318
11469
|
apiKey: config.apiKey || "not-needed"
|
|
11319
11470
|
});
|
|
11320
|
-
const response = await
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11471
|
+
const response = await withRetry4(
|
|
11472
|
+
() => client.chat.completions.create({
|
|
11473
|
+
model,
|
|
11474
|
+
messages: [{ role: "user", content: prompt }]
|
|
11475
|
+
})
|
|
11476
|
+
);
|
|
11324
11477
|
return response.choices[0]?.message?.content ?? "";
|
|
11325
11478
|
}
|
|
11326
11479
|
function extractDomainMentions(text2) {
|
|
@@ -11860,7 +12013,7 @@ function normalizeResult5(raw) {
|
|
|
11860
12013
|
}
|
|
11861
12014
|
|
|
11862
12015
|
// ../provider-cdp/src/adapter.ts
|
|
11863
|
-
var
|
|
12016
|
+
var connectionPool = /* @__PURE__ */ new Map();
|
|
11864
12017
|
function getConnection(config) {
|
|
11865
12018
|
if (!config.cdpEndpoint) {
|
|
11866
12019
|
throw new CDPProviderError("CDP_CONNECTION_REFUSED", "CDP endpoint not configured");
|
|
@@ -11871,14 +12024,13 @@ function getConnection(config) {
|
|
|
11871
12024
|
const parts = endpoint.split(":");
|
|
11872
12025
|
if (parts.length >= 1 && parts[0]) host = parts[0];
|
|
11873
12026
|
if (parts.length >= 2 && parts[1]) port = parseInt(parts[1], 10) || 9222;
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
sharedConnection = new CDPConnectionManager(host, port);
|
|
12027
|
+
const key = `${host}:${port}`;
|
|
12028
|
+
let conn = connectionPool.get(key);
|
|
12029
|
+
if (!conn) {
|
|
12030
|
+
conn = new CDPConnectionManager(host, port);
|
|
12031
|
+
connectionPool.set(key, conn);
|
|
11880
12032
|
}
|
|
11881
|
-
return
|
|
12033
|
+
return conn;
|
|
11882
12034
|
}
|
|
11883
12035
|
function getScreenshotDir2() {
|
|
11884
12036
|
return path4.join(os3.homedir(), ".canonry", "screenshots");
|
|
@@ -11937,35 +12089,40 @@ var cdpChatgptAdapter = {
|
|
|
11937
12089
|
async executeTrackedQuery(input, config) {
|
|
11938
12090
|
const conn = getConnection(config);
|
|
11939
12091
|
const target = chatgptTarget;
|
|
11940
|
-
const client = await conn.prepareForQuery(target);
|
|
11941
|
-
await target.submitQuery(client, input.keyword);
|
|
11942
|
-
await target.waitForResponse(client);
|
|
11943
|
-
const answerText = await target.extractAnswer(client);
|
|
11944
|
-
const groundingSources = await target.extractCitations(client);
|
|
11945
|
-
const screenshotId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
11946
|
-
const screenshotPath = path4.join(getScreenshotDir2(), `${screenshotId}.png`);
|
|
11947
|
-
let capturedScreenshotPath;
|
|
11948
12092
|
try {
|
|
11949
|
-
|
|
11950
|
-
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
);
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
12093
|
+
const client = await conn.prepareForQuery(target);
|
|
12094
|
+
await target.submitQuery(client, input.keyword);
|
|
12095
|
+
await target.waitForResponse(client);
|
|
12096
|
+
const answerText = await target.extractAnswer(client);
|
|
12097
|
+
const groundingSources = await target.extractCitations(client);
|
|
12098
|
+
const screenshotId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
12099
|
+
const screenshotPath = path4.join(getScreenshotDir2(), `${screenshotId}.png`);
|
|
12100
|
+
let capturedScreenshotPath;
|
|
12101
|
+
try {
|
|
12102
|
+
capturedScreenshotPath = await captureElementScreenshot(
|
|
12103
|
+
client,
|
|
12104
|
+
target.responseSelector,
|
|
12105
|
+
screenshotPath
|
|
12106
|
+
);
|
|
12107
|
+
} catch {
|
|
12108
|
+
}
|
|
12109
|
+
return {
|
|
12110
|
+
provider: "cdp:chatgpt",
|
|
12111
|
+
rawResponse: {
|
|
12112
|
+
answerText,
|
|
12113
|
+
groundingSources,
|
|
12114
|
+
extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12115
|
+
targetUrl: target.newConversationUrl
|
|
12116
|
+
},
|
|
12117
|
+
model: "chatgpt-web",
|
|
11960
12118
|
groundingSources,
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
}
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
};
|
|
12119
|
+
searchQueries: [input.keyword],
|
|
12120
|
+
screenshotPath: capturedScreenshotPath
|
|
12121
|
+
};
|
|
12122
|
+
} catch (err) {
|
|
12123
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12124
|
+
throw new Error(`[provider-cdp] ${msg}`);
|
|
12125
|
+
}
|
|
11969
12126
|
},
|
|
11970
12127
|
normalizeResult(raw) {
|
|
11971
12128
|
return normalizeResult5(raw);
|
|
@@ -11977,6 +12134,27 @@ var cdpChatgptAdapter = {
|
|
|
11977
12134
|
|
|
11978
12135
|
// ../provider-perplexity/src/normalize.ts
|
|
11979
12136
|
import OpenAI3 from "openai";
|
|
12137
|
+
|
|
12138
|
+
// ../provider-perplexity/src/utils.ts
|
|
12139
|
+
async function withRetry5(fn, options = {}) {
|
|
12140
|
+
const { maxRetries = 3, initialDelay = 1e3 } = options;
|
|
12141
|
+
let lastError;
|
|
12142
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
12143
|
+
try {
|
|
12144
|
+
return await fn();
|
|
12145
|
+
} catch (err) {
|
|
12146
|
+
lastError = err;
|
|
12147
|
+
if (attempt < maxRetries) {
|
|
12148
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
12149
|
+
console.warn(`[provider] Attempt ${attempt + 1} failed, retrying in ${delay}ms...`, err);
|
|
12150
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
12151
|
+
}
|
|
12152
|
+
}
|
|
12153
|
+
}
|
|
12154
|
+
throw lastError;
|
|
12155
|
+
}
|
|
12156
|
+
|
|
12157
|
+
// ../provider-perplexity/src/normalize.ts
|
|
11980
12158
|
var DEFAULT_MODEL5 = "sonar";
|
|
11981
12159
|
var BASE_URL = "https://api.perplexity.ai";
|
|
11982
12160
|
function validateConfig5(config) {
|
|
@@ -11995,10 +12173,12 @@ async function healthcheck5(config) {
|
|
|
11995
12173
|
if (!validation.ok) return validation;
|
|
11996
12174
|
try {
|
|
11997
12175
|
const client = new OpenAI3({ apiKey: config.apiKey, baseURL: BASE_URL });
|
|
11998
|
-
const response = await
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
|
|
12176
|
+
const response = await withRetry5(
|
|
12177
|
+
() => client.chat.completions.create({
|
|
12178
|
+
model: config.model ?? DEFAULT_MODEL5,
|
|
12179
|
+
messages: [{ role: "user", content: 'Say "ok"' }]
|
|
12180
|
+
})
|
|
12181
|
+
);
|
|
12002
12182
|
const text2 = response.choices[0]?.message?.content ?? "";
|
|
12003
12183
|
return {
|
|
12004
12184
|
ok: text2.length > 0,
|
|
@@ -12019,25 +12199,30 @@ async function executeTrackedQuery5(input) {
|
|
|
12019
12199
|
const model = input.config.model ?? DEFAULT_MODEL5;
|
|
12020
12200
|
const client = new OpenAI3({ apiKey: input.config.apiKey, baseURL: BASE_URL });
|
|
12021
12201
|
const prompt = buildPrompt4(input.keyword, input.location);
|
|
12022
|
-
|
|
12023
|
-
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
|
|
12027
|
-
|
|
12028
|
-
|
|
12029
|
-
|
|
12030
|
-
|
|
12031
|
-
|
|
12032
|
-
|
|
12033
|
-
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12202
|
+
try {
|
|
12203
|
+
const response = await withRetry5(
|
|
12204
|
+
() => client.chat.completions.create({
|
|
12205
|
+
model,
|
|
12206
|
+
messages: [{ role: "user", content: prompt }]
|
|
12207
|
+
})
|
|
12208
|
+
);
|
|
12209
|
+
const rawResponse = responseToRecord5(response);
|
|
12210
|
+
const citations = extractCitations(rawResponse);
|
|
12211
|
+
const groundingSources = citations.map((url) => ({
|
|
12212
|
+
uri: url,
|
|
12213
|
+
title: ""
|
|
12214
|
+
}));
|
|
12215
|
+
return {
|
|
12216
|
+
provider: "perplexity",
|
|
12217
|
+
rawResponse,
|
|
12218
|
+
model,
|
|
12219
|
+
groundingSources,
|
|
12220
|
+
searchQueries: [input.keyword]
|
|
12221
|
+
};
|
|
12222
|
+
} catch (err) {
|
|
12223
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12224
|
+
throw new Error(`[provider-perplexity] ${msg}`);
|
|
12225
|
+
}
|
|
12041
12226
|
}
|
|
12042
12227
|
function normalizeResult6(raw) {
|
|
12043
12228
|
const answerText = extractAnswerText3(raw.rawResponse);
|
|
@@ -12097,10 +12282,12 @@ function extractDomainFromUri4(uri) {
|
|
|
12097
12282
|
async function generateText5(prompt, config) {
|
|
12098
12283
|
const model = config.model ?? DEFAULT_MODEL5;
|
|
12099
12284
|
const client = new OpenAI3({ apiKey: config.apiKey, baseURL: BASE_URL });
|
|
12100
|
-
const response = await
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12285
|
+
const response = await withRetry5(
|
|
12286
|
+
() => client.chat.completions.create({
|
|
12287
|
+
model,
|
|
12288
|
+
messages: [{ role: "user", content: prompt }]
|
|
12289
|
+
})
|
|
12290
|
+
);
|
|
12104
12291
|
return response.choices[0]?.message?.content ?? "";
|
|
12105
12292
|
}
|
|
12106
12293
|
function responseToRecord5(response) {
|
|
@@ -12124,6 +12311,7 @@ var perplexityAdapter = {
|
|
|
12124
12311
|
displayName: "Perplexity",
|
|
12125
12312
|
mode: "api",
|
|
12126
12313
|
keyUrl: "https://www.perplexity.ai/settings/api",
|
|
12314
|
+
// Upstream model list: https://docs.perplexity.ai/guides/model-cards
|
|
12127
12315
|
modelRegistry: {
|
|
12128
12316
|
defaultModel: "sonar",
|
|
12129
12317
|
validationPattern: /^sonar/,
|
|
@@ -12352,7 +12540,7 @@ import crypto18 from "crypto";
|
|
|
12352
12540
|
import fs4 from "fs";
|
|
12353
12541
|
import path5 from "path";
|
|
12354
12542
|
import os4 from "os";
|
|
12355
|
-
import { and as and6, eq as eq17, inArray as inArray3 } from "drizzle-orm";
|
|
12543
|
+
import { and as and6, eq as eq17, inArray as inArray3, sql as sql5 } from "drizzle-orm";
|
|
12356
12544
|
|
|
12357
12545
|
// src/logger.ts
|
|
12358
12546
|
var IS_TTY = process.stdout.isTTY === true;
|
|
@@ -12514,12 +12702,12 @@ var JobRunner = class {
|
|
|
12514
12702
|
} else if (locationOverride) {
|
|
12515
12703
|
runLocation = locationOverride;
|
|
12516
12704
|
} else {
|
|
12517
|
-
const projectLocations =
|
|
12705
|
+
const projectLocations = parseJsonColumn(project.locations, []);
|
|
12518
12706
|
if (project.defaultLocation && projectLocations.length > 0) {
|
|
12519
12707
|
runLocation = projectLocations.find((l) => l.label === project.defaultLocation);
|
|
12520
12708
|
}
|
|
12521
12709
|
}
|
|
12522
|
-
const projectProviders = providerOverride ??
|
|
12710
|
+
const projectProviders = providerOverride ?? parseJsonColumn(project.providers, []);
|
|
12523
12711
|
activeProviders = this.registry.getForProject(projectProviders);
|
|
12524
12712
|
if (activeProviders.length === 0) {
|
|
12525
12713
|
throw new Error("No providers configured. Add at least one provider API key.");
|
|
@@ -12530,7 +12718,7 @@ var JobRunner = class {
|
|
|
12530
12718
|
const competitorDomains = projectCompetitors.map((c) => c.domain);
|
|
12531
12719
|
const allDomains = effectiveDomains({
|
|
12532
12720
|
canonicalDomain: project.canonicalDomain,
|
|
12533
|
-
ownedDomains:
|
|
12721
|
+
ownedDomains: parseJsonColumn(project.ownedDomains, [])
|
|
12534
12722
|
});
|
|
12535
12723
|
const executionContext = {
|
|
12536
12724
|
providerCount: activeProviders.length,
|
|
@@ -12741,22 +12929,19 @@ var JobRunner = class {
|
|
|
12741
12929
|
}
|
|
12742
12930
|
}
|
|
12743
12931
|
incrementUsage(scope, metric, count) {
|
|
12744
|
-
const now = /* @__PURE__ */ new Date();
|
|
12745
|
-
const period = now.
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12753
|
-
|
|
12754
|
-
|
|
12755
|
-
|
|
12756
|
-
|
|
12757
|
-
updatedAt: now.toISOString()
|
|
12758
|
-
}).run();
|
|
12759
|
-
}
|
|
12932
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12933
|
+
const period = now.slice(0, 10);
|
|
12934
|
+
this.db.insert(usageCounters).values({
|
|
12935
|
+
id: crypto18.randomUUID(),
|
|
12936
|
+
scope,
|
|
12937
|
+
period,
|
|
12938
|
+
metric,
|
|
12939
|
+
count,
|
|
12940
|
+
updatedAt: now
|
|
12941
|
+
}).onConflictDoUpdate({
|
|
12942
|
+
target: [usageCounters.scope, usageCounters.period, usageCounters.metric],
|
|
12943
|
+
set: { count: sql5`${usageCounters.count} + ${count}`, updatedAt: now }
|
|
12944
|
+
}).run();
|
|
12760
12945
|
}
|
|
12761
12946
|
flushProviderUsage(projectId, providerDispatchCounts) {
|
|
12762
12947
|
for (const [providerName, count] of providerDispatchCounts.entries()) {
|
|
@@ -12957,7 +13142,7 @@ function matchesBrandKey(candidateKey, brandKeys) {
|
|
|
12957
13142
|
|
|
12958
13143
|
// src/gsc-sync.ts
|
|
12959
13144
|
import crypto19 from "crypto";
|
|
12960
|
-
import { eq as eq18, and as and7, sql as
|
|
13145
|
+
import { eq as eq18, and as and7, sql as sql6 } from "drizzle-orm";
|
|
12961
13146
|
var log2 = createLogger("GscSync");
|
|
12962
13147
|
function formatDate2(d) {
|
|
12963
13148
|
return d.toISOString().split("T")[0];
|
|
@@ -13011,8 +13196,8 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
13011
13196
|
db.delete(gscSearchData).where(
|
|
13012
13197
|
and7(
|
|
13013
13198
|
eq18(gscSearchData.projectId, projectId),
|
|
13014
|
-
|
|
13015
|
-
|
|
13199
|
+
sql6`${gscSearchData.date} >= ${startDate}`,
|
|
13200
|
+
sql6`${gscSearchData.date} <= ${endDate}`
|
|
13016
13201
|
)
|
|
13017
13202
|
).run();
|
|
13018
13203
|
const batchSize = 500;
|
|
@@ -13471,7 +13656,7 @@ var Scheduler = class {
|
|
|
13471
13656
|
nextRunAt,
|
|
13472
13657
|
updatedAt: now
|
|
13473
13658
|
}).where(eq20(schedules.id, currentSchedule.id)).run();
|
|
13474
|
-
const scheduleProviders =
|
|
13659
|
+
const scheduleProviders = parseJsonColumn(currentSchedule.providers, []);
|
|
13475
13660
|
const providers = scheduleProviders.length > 0 ? scheduleProviders : void 0;
|
|
13476
13661
|
log4.info("run.triggered", { runId, projectName: project.name, providers: providers ?? "all" });
|
|
13477
13662
|
this.callbacks.onRunCreated(runId, projectId, providers);
|