@ainyc/canonry 1.45.0 → 1.45.1

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.
@@ -23,7 +23,7 @@ import {
23
23
  runs,
24
24
  schedules,
25
25
  usageCounters
26
- } from "./chunk-SVPQUYTG.js";
26
+ } from "./chunk-WBV2D7FB.js";
27
27
 
28
28
  // src/config.ts
29
29
  import fs from "fs";
@@ -268,7 +268,7 @@ import crypto22 from "crypto";
268
268
  import fs5 from "fs";
269
269
  import path6 from "path";
270
270
  import { fileURLToPath } from "url";
271
- import { eq as eq23 } from "drizzle-orm";
271
+ import { eq as eq23, sql as sql6 } from "drizzle-orm";
272
272
  import Fastify from "fastify";
273
273
 
274
274
  // ../contracts/src/config-schema.ts
@@ -15085,6 +15085,70 @@ function serializeSessionCookie(opts) {
15085
15085
  }
15086
15086
  return parts.join("; ");
15087
15087
  }
15088
+ function migrateDbCredentialsToConfig(db, config) {
15089
+ try {
15090
+ const googleColCheck = db.all(sql6.raw(
15091
+ `SELECT COUNT(*) as c FROM pragma_table_info('google_connections') WHERE name = 'access_token'`
15092
+ ));
15093
+ if (googleColCheck[0]?.c) {
15094
+ const rows = db.all(sql6.raw(
15095
+ `SELECT domain, connection_type, property_id, sitemap_url, access_token, refresh_token, token_expires_at, scopes, created_at, updated_at FROM google_connections WHERE refresh_token IS NOT NULL AND refresh_token != ''`
15096
+ ));
15097
+ let migrated = 0;
15098
+ for (const row of rows) {
15099
+ const connType = row.connection_type;
15100
+ const existing = getGoogleConnection(config, row.domain, connType);
15101
+ if (existing?.refreshToken) continue;
15102
+ upsertGoogleConnection(config, {
15103
+ domain: row.domain,
15104
+ connectionType: connType,
15105
+ propertyId: row.property_id ?? null,
15106
+ sitemapUrl: row.sitemap_url ?? null,
15107
+ accessToken: row.access_token ?? void 0,
15108
+ refreshToken: row.refresh_token ?? null,
15109
+ tokenExpiresAt: row.token_expires_at ?? null,
15110
+ scopes: parseJsonColumn(row.scopes, []),
15111
+ createdAt: row.created_at,
15112
+ updatedAt: row.updated_at
15113
+ });
15114
+ migrated++;
15115
+ }
15116
+ if (migrated > 0) {
15117
+ saveConfigPatch({ google: config.google });
15118
+ log8.info("credentials.migrated", { type: "google", count: migrated });
15119
+ }
15120
+ }
15121
+ const gaColCheck = db.all(sql6.raw(
15122
+ `SELECT COUNT(*) as c FROM pragma_table_info('ga_connections') WHERE name = 'private_key'`
15123
+ ));
15124
+ if (gaColCheck[0]?.c) {
15125
+ const rows = db.all(sql6.raw(
15126
+ `SELECT id, project_id, property_id, client_email, private_key, created_at, updated_at FROM ga_connections WHERE private_key IS NOT NULL AND private_key != ''`
15127
+ ));
15128
+ let migrated = 0;
15129
+ for (const row of rows) {
15130
+ const project = db.select({ name: projects.name }).from(projects).where(eq23(projects.id, row.project_id)).get();
15131
+ if (!project) continue;
15132
+ const existing = getGa4Connection(config, project.name);
15133
+ if (existing?.privateKey) continue;
15134
+ upsertGa4Connection(config, {
15135
+ projectName: project.name,
15136
+ propertyId: row.property_id,
15137
+ clientEmail: row.client_email,
15138
+ privateKey: row.private_key,
15139
+ createdAt: row.created_at,
15140
+ updatedAt: row.updated_at
15141
+ });
15142
+ migrated++;
15143
+ }
15144
+ if (migrated > 0) {
15145
+ saveConfigPatch({ ga4: config.ga4 });
15146
+ log8.info("credentials.migrated", { type: "ga4", count: migrated });
15147
+ }
15148
+ }
15149
+ } catch {
15150
+ }
15151
+ }
15088
15152
  async function createServer(opts) {
15089
15153
  const logger = opts.logger === false ? false : process.stdout.isTTY ? {
15090
15154
  transport: {
@@ -15109,6 +15173,7 @@ async function createServer(opts) {
15109
15173
  quota: opts.config.geminiQuota
15110
15174
  };
15111
15175
  }
15176
+ migrateDbCredentialsToConfig(opts.db, opts.config);
15112
15177
  log8.info("providers.configured", { providers: Object.keys(providers).filter((k) => {
15113
15178
  const p = providers[k];
15114
15179
  return p?.apiKey || p?.baseUrl || p?.vertexProject;
@@ -175,10 +175,6 @@ var googleConnections = sqliteTable("google_connections", {
175
175
  connectionType: text("connection_type").notNull(),
176
176
  propertyId: text("property_id"),
177
177
  sitemapUrl: text("sitemap_url"),
178
- // WARNING: Authentication material should be stored in config.yaml per CLAUDE.md
179
- accessToken: text("access_token"),
180
- refreshToken: text("refresh_token"),
181
- tokenExpiresAt: text("token_expires_at"),
182
178
  scopes: text("scopes").notNull().default("[]"),
183
179
  createdAt: text("created_at").notNull(),
184
180
  updatedAt: text("updated_at").notNull()
@@ -295,8 +291,6 @@ var gaConnections = sqliteTable("ga_connections", {
295
291
  projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
296
292
  propertyId: text("property_id").notNull(),
297
293
  clientEmail: text("client_email").notNull(),
298
- // WARNING: Authentication material should be stored in config.yaml per CLAUDE.md
299
- privateKey: text("private_key").notNull(),
300
294
  createdAt: text("created_at").notNull(),
301
295
  updatedAt: text("updated_at").notNull()
302
296
  }, (table) => [
@@ -819,6 +813,10 @@ var MIGRATIONS = [
819
813
  created_at TEXT NOT NULL
820
814
  )`,
821
815
  `CREATE UNIQUE INDEX IF NOT EXISTS idx_bing_coverage_snap_project_date ON bing_coverage_snapshots(project_id, date)`
816
+ // v27: Credential columns removed from Drizzle schema — credentials now live in config.yaml.
817
+ // Physical columns (access_token, refresh_token, token_expires_at on google_connections;
818
+ // private_key on ga_connections) intentionally retained in DB for one-time migration in server.ts.
819
+ // SQLite does not support DROP COLUMN; no SQL to execute.
822
820
  ];
823
821
  function isDuplicateColumnError(err) {
824
822
  if (!(err instanceof Error)) return false;
package/dist/cli.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  setGoogleAuthConfig,
29
29
  showFirstRunNotice,
30
30
  trackEvent
31
- } from "./chunk-B4EP44AR.js";
31
+ } from "./chunk-6HJVQBQM.js";
32
32
  import {
33
33
  apiKeys,
34
34
  competitors,
@@ -38,7 +38,7 @@ import {
38
38
  projects,
39
39
  querySnapshots,
40
40
  runs
41
- } from "./chunk-SVPQUYTG.js";
41
+ } from "./chunk-WBV2D7FB.js";
42
42
 
43
43
  // src/cli.ts
44
44
  import { pathToFileURL } from "url";
@@ -355,7 +355,7 @@ async function backfillAnswerVisibilityCommand(opts) {
355
355
  console.log(` Errors: ${providerErrors}`);
356
356
  }
357
357
  async function backfillInsightsCommand(project, opts) {
358
- const { IntelligenceService } = await import("./intelligence-service-TXWOESFH.js");
358
+ const { IntelligenceService } = await import("./intelligence-service-QF6E4HBV.js");
359
359
  const config = loadConfig();
360
360
  const db = createClient(config.database);
361
361
  migrate(db);
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createServer,
3
3
  loadConfig
4
- } from "./chunk-B4EP44AR.js";
5
- import "./chunk-SVPQUYTG.js";
4
+ } from "./chunk-6HJVQBQM.js";
5
+ import "./chunk-WBV2D7FB.js";
6
6
  export {
7
7
  createServer,
8
8
  loadConfig
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-SVPQUYTG.js";
3
+ } from "./chunk-WBV2D7FB.js";
4
4
  export {
5
5
  IntelligenceService
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "1.45.0",
3
+ "version": "1.45.1",
4
4
  "type": "module",
5
5
  "description": "The ultimate open-source AEO monitoring tool - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -56,18 +56,18 @@
56
56
  "tsx": "^4.19.0",
57
57
  "@ainyc/canonry-api-routes": "0.0.0",
58
58
  "@ainyc/canonry-config": "0.0.0",
59
- "@ainyc/canonry-contracts": "0.0.0",
60
59
  "@ainyc/canonry-db": "0.0.0",
61
- "@ainyc/canonry-integration-bing": "0.0.0",
60
+ "@ainyc/canonry-contracts": "0.0.0",
62
61
  "@ainyc/canonry-intelligence": "0.0.0",
62
+ "@ainyc/canonry-integration-bing": "0.0.0",
63
63
  "@ainyc/canonry-integration-wordpress": "0.0.0",
64
- "@ainyc/canonry-integration-google": "0.0.0",
65
64
  "@ainyc/canonry-provider-cdp": "0.0.0",
66
- "@ainyc/canonry-provider-gemini": "0.0.0",
67
65
  "@ainyc/canonry-provider-local": "0.0.0",
68
- "@ainyc/canonry-provider-openai": "0.0.0",
66
+ "@ainyc/canonry-integration-google": "0.0.0",
69
67
  "@ainyc/canonry-provider-claude": "0.0.0",
70
- "@ainyc/canonry-provider-perplexity": "0.0.0"
68
+ "@ainyc/canonry-provider-openai": "0.0.0",
69
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
70
+ "@ainyc/canonry-provider-gemini": "0.0.0"
71
71
  },
72
72
  "scripts": {
73
73
  "build": "tsup && tsx build-web.ts",