@canonry/canonry 7.68.0 → 7.68.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.
- package/README.md +2 -0
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -0
- package/dist/{chunk-K54WGCZV.js → chunk-F4KTLNW3.js} +3 -3
- package/dist/{chunk-QXCQSRHL.js → chunk-KGJ7NDUY.js} +1 -1
- package/dist/{chunk-LABVR6K7.js → chunk-LO2EII7V.js} +1 -1
- package/dist/{cli-commands-LWI2NEWW.js → cli-commands-3RTJR7FD.js} +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +66 -66
- package/dist/index.js +1 -1
- package/dist/{init-WTAVKFGR.js → init-XDFRSNJ6.js} +1 -1
- package/dist/{serve-3BSLRICO.js → serve-RR6YYFKA.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
[](./LICENSE)
|
|
4
4
|
[](https://www.npmjs.com/package/@canonry/canonry)
|
|
5
|
+
[](https://discord.gg/8K9yY7GywJ)
|
|
6
|
+
[](https://x.com/canonry_ai)
|
|
5
7
|
|
|
6
8
|
Canonry is an **agent-first (CLI, MCP, API), open-source AEO operating platform with a comprehensive web UI.** Track AI visibility over time, investigate changes across search and traffic, and measure progress after you or your agent acts.
|
|
7
9
|
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
`cnry seo context <project>` lists configured sources, exact scopes and permissions. Use `seo profile list/show/set` to manage profiles, `seo overview`, `seo keyword-metrics`, `seo domain-intelligence`, `seo ranked-keywords` and `seo market-rankings` for stored evidence. Preserve `--profile-id` and `--run-id` when paging with `--limit` and `--offset`. `seo market-rankings` is the site's Google position for its tracked non-brand queries in each market (the same queries AI visibility measures), searched from that market's location; `--market` and `--region` narrow the rows, `--outcome` (`needs-work`, `page-1`, `ranks-11-20`, `ranks-21-plus`, `not-ranked`, `partly-checked`, `rival-ahead`, `failed`, `cancelled`) and `--search <text>` filter them, and `--sort=rank` puts the closest to page 1 first (`--sort=-rank` the furthest). `searchStatus` says how each search ended: a null rank in a `completed` or `partial` row means not in the checked results (`depth`, lower for a partial search, whose unranked rows are `partly-checked`, never `not-ranked`), and a `failed` or `cancelled` row has no rank because the search returned nothing. `seo market-summary` counts the rows by outcome for the profile (one group per region), `--region` (one group per market) or `--market`.
|
|
6
6
|
|
|
7
|
+
To set up a profile, read `seo context` for the `connectionId` and supported scopes, then run `seo profile set <project> <profile-id> --file profile.json`. Saving never starts paid work, but an enabled `seo-sync` schedule refreshes every saved profile at its next firing. A profile holds `name`, `connectionId`, `capabilities`, `targets`, `keywords`, `locationCode`, `languageCode`, `limit` and `scope`. `targets` takes at most 20 plain hostnames: `{"kind":"domain","value":"example.com","includeSubdomains":true}` for a whole domain (domain intelligence requires one) or `"kind":"host"` with `"includeSubdomains":false` for one exact host. `keyword-metrics` requires at least one keyword. `locationCode` is the provider's location code (2840 is the United States). `scope` is `{"kind":"project"}` on Simple projects; Advanced profiles add the scope key and `expectedPlanRevision` from `seo context`. Overview metrics describe the first target only. To compare competitors, put the project's tracked competitors (`cnry competitor list <project>`), not domains taken from AI citations, in a `domain-intelligence` profile with the same location and language as the site's own profile.
|
|
8
|
+
|
|
9
|
+
Market rankings need their own profile: `"capabilities":["market-rankings"]`, exactly one target that is one of the project's own domains, `"keywords":[]`, and `rankings` with `locations`, `depth` (10 to 100 in steps of 10), `device` (`desktop` or `mobile`) and `searchText` (`query` or `query-without-market-region`). They search the project's tracked non-brand queries, so the project needs a brand name to tell branded queries apart. Every market needs a location, or the profile is refused with the markets that lack one. A Simple project with locations searches every tracked query in each location, keyed by its location label; an Advanced market resolves through its own key, then its group and that group's parents. Only a project with no locations or markets falls back to the profile's `locationCode`; an explicit `project` key gives that location a readable label. The CLI has no location lookup: take each code and its label from the provider's location list (for example `200623` is the Dallas-Ft. Worth metro). Tracked competitors are reported in each row without further setup.
|
|
10
|
+
|
|
7
11
|
After explicit approval for the profile and bounded work, prepare `seo refresh-intent <project> <profile-id>`, then pass its token and a stable retry key to `seo sync --intent-token ... --idempotency-key ...`. A `seo-sync` schedule (`schedule set <project> --kind seo-sync --cron '0 7 2 * *'`) refreshes every saved profile on its cadence; it is standing approval for recurring paid work, so set one only when the operator asked for that cadence. Enabling it needs `seo.run`. `cnry doctor --project <project> --check seo.data.recent-refresh` warns, and the health pass alerts, when the latest scheduled refresh failed (with its reason) or none completed within two days of its due date. Inspect `seo runs` and `seo run show`; `seo run cancel` stops undispatched work. Use `--format json` for API-shaped output. Hosted budgets are internal. Never infer actual traffic from provider estimates or broaden a Property into a domain.
|
|
8
12
|
|
|
9
13
|
The CLI is invoked as `cnry` (short form) or `canonry` — both ship with the `@canonry/canonry` npm package and behave identically. This reference uses `cnry`.
|
|
@@ -6829,7 +6829,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
6829
6829
|
options: { access: stringOption() },
|
|
6830
6830
|
run: async (input) => {
|
|
6831
6831
|
if (input.positionals.length > 1) throw usageError("Expected at most one command group");
|
|
6832
|
-
const [{ printCliCatalog }, { REGISTERED_CLI_COMMANDS: REGISTERED_CLI_COMMANDS2 }] = await Promise.all([import("./cli-catalog-ONYERYPV.js"), import("./cli-commands-
|
|
6832
|
+
const [{ printCliCatalog }, { REGISTERED_CLI_COMMANDS: REGISTERED_CLI_COMMANDS2 }] = await Promise.all([import("./cli-catalog-ONYERYPV.js"), import("./cli-commands-3RTJR7FD.js")]);
|
|
6833
6833
|
printCliCatalog(REGISTERED_CLI_COMMANDS2, input.format, input.positionals[0], getString(input.values, "access"));
|
|
6834
6834
|
}
|
|
6835
6835
|
},
|
|
@@ -6878,7 +6878,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
6878
6878
|
},
|
|
6879
6879
|
allowPositionals: false,
|
|
6880
6880
|
run: async (input) => {
|
|
6881
|
-
const { initCommand } = await import("./init-
|
|
6881
|
+
const { initCommand } = await import("./init-XDFRSNJ6.js");
|
|
6882
6882
|
await initCommand({
|
|
6883
6883
|
force: getBoolean(input.values, "force"),
|
|
6884
6884
|
ref: getString(input.values, "ref"),
|
|
@@ -6933,7 +6933,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
6933
6933
|
allowPositionals: false,
|
|
6934
6934
|
run: async (input) => {
|
|
6935
6935
|
applyServerEnv(input.values);
|
|
6936
|
-
const { serveCommand } = await import("./serve-
|
|
6936
|
+
const { serveCommand } = await import("./serve-RR6YYFKA.js");
|
|
6937
6937
|
await serveCommand(input.format);
|
|
6938
6938
|
}
|
|
6939
6939
|
},
|
|
@@ -5804,7 +5804,7 @@ function nonBlank(value) {
|
|
|
5804
5804
|
return trimmed ? trimmed : void 0;
|
|
5805
5805
|
}
|
|
5806
5806
|
function resolveBuildCommit(env = process.env) {
|
|
5807
|
-
const embedded = true ? "
|
|
5807
|
+
const embedded = true ? "2631ed359be107c3e47aee3905b706f664443b08" : void 0;
|
|
5808
5808
|
return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
|
|
5809
5809
|
}
|
|
5810
5810
|
function resolveInstanceIdentity(env = process.env) {
|
|
@@ -47,7 +47,7 @@ function queueServeHandoff() {
|
|
|
47
47
|
async function runPendingServeHandoff(format) {
|
|
48
48
|
if (!pendingServeHandoff) return;
|
|
49
49
|
pendingServeHandoff = false;
|
|
50
|
-
const { serveCommand } = await import("./serve-
|
|
50
|
+
const { serveCommand } = await import("./serve-RR6YYFKA.js");
|
|
51
51
|
await serveCommand(format);
|
|
52
52
|
}
|
|
53
53
|
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node --import tsx
|
|
2
2
|
import {
|
|
3
3
|
REGISTERED_CLI_COMMANDS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-F4KTLNW3.js";
|
|
5
5
|
import {
|
|
6
6
|
buildSetupState,
|
|
7
7
|
runPendingServeHandoff
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LO2EII7V.js";
|
|
9
9
|
import "./chunk-6GO5VVAC.js";
|
|
10
10
|
import "./chunk-R42VEDCB.js";
|
|
11
11
|
import "./chunk-VJWDBFSL.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -70,10 +70,10 @@ declare const googleAdsAccessibleCustomerDtoSchema: z.ZodObject<{
|
|
|
70
70
|
level: z.ZodNumber;
|
|
71
71
|
status: z.ZodEnum<{
|
|
72
72
|
unknown: "unknown";
|
|
73
|
+
canceled: "canceled";
|
|
73
74
|
enabled: "enabled";
|
|
74
75
|
suspended: "suspended";
|
|
75
76
|
closed: "closed";
|
|
76
|
-
canceled: "canceled";
|
|
77
77
|
unspecified: "unspecified";
|
|
78
78
|
}>;
|
|
79
79
|
}, z.core.$strict>;
|
|
@@ -92,10 +92,10 @@ declare const googleAdsAccessibleCustomersResponseSchema: z.ZodObject<{
|
|
|
92
92
|
level: z.ZodNumber;
|
|
93
93
|
status: z.ZodEnum<{
|
|
94
94
|
unknown: "unknown";
|
|
95
|
+
canceled: "canceled";
|
|
95
96
|
enabled: "enabled";
|
|
96
97
|
suspended: "suspended";
|
|
97
98
|
closed: "closed";
|
|
98
|
-
canceled: "canceled";
|
|
99
99
|
unspecified: "unspecified";
|
|
100
100
|
}>;
|
|
101
101
|
}, z.core.$strict>>;
|
|
@@ -115,8 +115,8 @@ declare const googleAdsEffectiveGoalGraphDtoSchema: z.ZodObject<{
|
|
|
115
115
|
campaigns: z.ZodArray<z.ZodObject<{
|
|
116
116
|
campaignId: z.ZodString;
|
|
117
117
|
goalConfigLevel: z.ZodEnum<{
|
|
118
|
-
customer: "customer";
|
|
119
118
|
campaign: "campaign";
|
|
119
|
+
customer: "customer";
|
|
120
120
|
}>;
|
|
121
121
|
customGoalId: z.ZodNullable<z.ZodString>;
|
|
122
122
|
missingCustomGoalId: z.ZodNullable<z.ZodString>;
|
|
@@ -180,10 +180,10 @@ declare const googleAdsRawSnapshotDtoSchema: z.ZodObject<{
|
|
|
180
180
|
level: z.ZodNumber;
|
|
181
181
|
status: z.ZodEnum<{
|
|
182
182
|
unknown: "unknown";
|
|
183
|
+
canceled: "canceled";
|
|
183
184
|
enabled: "enabled";
|
|
184
185
|
suspended: "suspended";
|
|
185
186
|
closed: "closed";
|
|
186
|
-
canceled: "canceled";
|
|
187
187
|
unspecified: "unspecified";
|
|
188
188
|
}>;
|
|
189
189
|
}, z.core.$strict>>;
|
|
@@ -208,8 +208,8 @@ declare const googleAdsRawSnapshotDtoSchema: z.ZodObject<{
|
|
|
208
208
|
status: z.ZodEnum<{
|
|
209
209
|
unknown: "unknown";
|
|
210
210
|
enabled: "enabled";
|
|
211
|
-
removed: "removed";
|
|
212
211
|
paused: "paused";
|
|
212
|
+
removed: "removed";
|
|
213
213
|
}>;
|
|
214
214
|
advertisingChannelType: z.ZodNullable<z.ZodString>;
|
|
215
215
|
biddingStrategyType: z.ZodNullable<z.ZodString>;
|
|
@@ -221,8 +221,8 @@ declare const googleAdsRawSnapshotDtoSchema: z.ZodObject<{
|
|
|
221
221
|
status: z.ZodEnum<{
|
|
222
222
|
unknown: "unknown";
|
|
223
223
|
enabled: "enabled";
|
|
224
|
-
removed: "removed";
|
|
225
224
|
hidden: "hidden";
|
|
225
|
+
removed: "removed";
|
|
226
226
|
}>;
|
|
227
227
|
category: z.ZodString;
|
|
228
228
|
origin: z.ZodString;
|
|
@@ -249,8 +249,8 @@ declare const googleAdsRawSnapshotDtoSchema: z.ZodObject<{
|
|
|
249
249
|
campaignGoalConfigurations: z.ZodArray<z.ZodObject<{
|
|
250
250
|
campaignId: z.ZodString;
|
|
251
251
|
goalConfigLevel: z.ZodEnum<{
|
|
252
|
-
customer: "customer";
|
|
253
252
|
campaign: "campaign";
|
|
253
|
+
customer: "customer";
|
|
254
254
|
}>;
|
|
255
255
|
customGoalId: z.ZodNullable<z.ZodString>;
|
|
256
256
|
}, z.core.$strict>>;
|
|
@@ -331,10 +331,10 @@ declare const gtmRawSnapshotDtoSchema: z.ZodObject<{
|
|
|
331
331
|
connectionId: z.ZodString;
|
|
332
332
|
runId: z.ZodString;
|
|
333
333
|
kind: z.ZodEnum<{
|
|
334
|
-
live: "live";
|
|
335
|
-
draft: "draft";
|
|
336
334
|
accounts: "accounts";
|
|
337
335
|
container: "container";
|
|
336
|
+
live: "live";
|
|
337
|
+
draft: "draft";
|
|
338
338
|
}>;
|
|
339
339
|
accountId: z.ZodNullable<z.ZodString>;
|
|
340
340
|
containerId: z.ZodNullable<z.ZodString>;
|
|
@@ -1358,8 +1358,8 @@ declare const seoMarketRankingSchema: z.ZodObject<{
|
|
|
1358
1358
|
searchStatus: z.ZodEnum<{
|
|
1359
1359
|
partial: "partial";
|
|
1360
1360
|
failed: "failed";
|
|
1361
|
-
completed: "completed";
|
|
1362
1361
|
cancelled: "cancelled";
|
|
1362
|
+
completed: "completed";
|
|
1363
1363
|
}>;
|
|
1364
1364
|
rankOrganic: z.ZodNullable<z.ZodNumber>;
|
|
1365
1365
|
rankAbsolute: z.ZodNullable<z.ZodNumber>;
|
|
@@ -1506,8 +1506,8 @@ declare const seoResultsSchema: z.ZodObject<{
|
|
|
1506
1506
|
searchStatus: z.ZodEnum<{
|
|
1507
1507
|
partial: "partial";
|
|
1508
1508
|
failed: "failed";
|
|
1509
|
-
completed: "completed";
|
|
1510
1509
|
cancelled: "cancelled";
|
|
1510
|
+
completed: "completed";
|
|
1511
1511
|
}>;
|
|
1512
1512
|
rankOrganic: z.ZodNullable<z.ZodNumber>;
|
|
1513
1513
|
rankAbsolute: z.ZodNullable<z.ZodNumber>;
|
|
@@ -1659,7 +1659,7 @@ declare const seoProfiles: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
1659
1659
|
languageCode: string;
|
|
1660
1660
|
limit: number;
|
|
1661
1661
|
scope: {
|
|
1662
|
-
kind: "
|
|
1662
|
+
kind: "group" | "market" | "property" | "project";
|
|
1663
1663
|
key?: string | undefined;
|
|
1664
1664
|
expectedPlanRevision?: number | undefined;
|
|
1665
1665
|
};
|
|
@@ -1699,7 +1699,7 @@ declare const seoProfiles: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
1699
1699
|
languageCode: string;
|
|
1700
1700
|
limit: number;
|
|
1701
1701
|
scope: {
|
|
1702
|
-
kind: "
|
|
1702
|
+
kind: "group" | "market" | "property" | "project";
|
|
1703
1703
|
key?: string | undefined;
|
|
1704
1704
|
expectedPlanRevision?: number | undefined;
|
|
1705
1705
|
};
|
|
@@ -1891,7 +1891,7 @@ declare const seoJobs: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
1891
1891
|
languageCode: string;
|
|
1892
1892
|
limit: number;
|
|
1893
1893
|
scope: {
|
|
1894
|
-
kind: "
|
|
1894
|
+
kind: "group" | "market" | "property" | "project";
|
|
1895
1895
|
key?: string | undefined;
|
|
1896
1896
|
expectedPlanRevision?: number | undefined;
|
|
1897
1897
|
};
|
|
@@ -1931,7 +1931,7 @@ declare const seoJobs: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
1931
1931
|
languageCode: string;
|
|
1932
1932
|
limit: number;
|
|
1933
1933
|
scope: {
|
|
1934
|
-
kind: "
|
|
1934
|
+
kind: "group" | "market" | "property" | "project";
|
|
1935
1935
|
key?: string | undefined;
|
|
1936
1936
|
expectedPlanRevision?: number | undefined;
|
|
1937
1937
|
};
|
|
@@ -2085,7 +2085,7 @@ declare const seoJobs: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2085
2085
|
tableName: "seo_jobs";
|
|
2086
2086
|
dataType: "string";
|
|
2087
2087
|
columnType: "SQLiteText";
|
|
2088
|
-
data: "queued" | "
|
|
2088
|
+
data: "queued" | "partial" | "failed" | "cancelled" | "running" | "completed" | "reconciliation-required";
|
|
2089
2089
|
driverParam: string;
|
|
2090
2090
|
notNull: true;
|
|
2091
2091
|
hasDefault: false;
|
|
@@ -2098,7 +2098,7 @@ declare const seoJobs: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2098
2098
|
generated: undefined;
|
|
2099
2099
|
}, {}, {
|
|
2100
2100
|
length: number | undefined;
|
|
2101
|
-
$type: "queued" | "
|
|
2101
|
+
$type: "queued" | "partial" | "failed" | "cancelled" | "running" | "completed" | "reconciliation-required";
|
|
2102
2102
|
}>;
|
|
2103
2103
|
cancelRequested: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
2104
2104
|
name: "cancel_requested";
|
|
@@ -2262,7 +2262,7 @@ declare const seoTasks: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2262
2262
|
tableName: "seo_tasks";
|
|
2263
2263
|
dataType: "string";
|
|
2264
2264
|
columnType: "SQLiteText";
|
|
2265
|
-
data: "queued" | "
|
|
2265
|
+
data: "queued" | "partial" | "failed" | "cancelled" | "running" | "completed" | "reconciliation-required";
|
|
2266
2266
|
driverParam: string;
|
|
2267
2267
|
notNull: true;
|
|
2268
2268
|
hasDefault: false;
|
|
@@ -2275,7 +2275,7 @@ declare const seoTasks: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2275
2275
|
generated: undefined;
|
|
2276
2276
|
}, {}, {
|
|
2277
2277
|
length: number | undefined;
|
|
2278
|
-
$type: "queued" | "
|
|
2278
|
+
$type: "queued" | "partial" | "failed" | "cancelled" | "running" | "completed" | "reconciliation-required";
|
|
2279
2279
|
}>;
|
|
2280
2280
|
leaseOwner: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
2281
2281
|
name: "lease_owner";
|
|
@@ -2793,7 +2793,7 @@ declare const projects: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2793
2793
|
tableName: "projects";
|
|
2794
2794
|
dataType: "string";
|
|
2795
2795
|
columnType: "SQLiteText";
|
|
2796
|
-
data: "
|
|
2796
|
+
data: "full" | "competitors";
|
|
2797
2797
|
driverParam: string;
|
|
2798
2798
|
notNull: false;
|
|
2799
2799
|
hasDefault: false;
|
|
@@ -2806,7 +2806,7 @@ declare const projects: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
2806
2806
|
generated: undefined;
|
|
2807
2807
|
}, {}, {
|
|
2808
2808
|
length: number | undefined;
|
|
2809
|
-
$type: "
|
|
2809
|
+
$type: "full" | "competitors";
|
|
2810
2810
|
}>;
|
|
2811
2811
|
country: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
2812
2812
|
name: "country";
|
|
@@ -6064,7 +6064,7 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
6064
6064
|
tableName: "query_snapshots";
|
|
6065
6065
|
dataType: "string";
|
|
6066
6066
|
columnType: "SQLiteText";
|
|
6067
|
-
data: "unknown" | "
|
|
6067
|
+
data: "unknown" | "used" | "not-used" | "not-applicable";
|
|
6068
6068
|
driverParam: string;
|
|
6069
6069
|
notNull: false;
|
|
6070
6070
|
hasDefault: false;
|
|
@@ -6077,7 +6077,7 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
6077
6077
|
generated: undefined;
|
|
6078
6078
|
}, {}, {
|
|
6079
6079
|
length: number | undefined;
|
|
6080
|
-
$type: "unknown" | "
|
|
6080
|
+
$type: "unknown" | "used" | "not-used" | "not-applicable";
|
|
6081
6081
|
}>;
|
|
6082
6082
|
retrievalContract: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
6083
6083
|
name: "retrieval_contract";
|
|
@@ -6425,8 +6425,8 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
6425
6425
|
status?: string | null | undefined;
|
|
6426
6426
|
}[];
|
|
6427
6427
|
searchQueries: string[];
|
|
6428
|
-
retrievalStatus: "unknown" | "
|
|
6429
|
-
citationBasis: "
|
|
6428
|
+
retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
|
|
6429
|
+
citationBasis: "answer-support" | "explicit-citation" | "mixed" | "none";
|
|
6430
6430
|
citationMeasurable: boolean;
|
|
6431
6431
|
directSourceUrls: boolean;
|
|
6432
6432
|
location: {
|
|
@@ -6530,8 +6530,8 @@ declare const querySnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
6530
6530
|
status?: string | null | undefined;
|
|
6531
6531
|
}[];
|
|
6532
6532
|
searchQueries: string[];
|
|
6533
|
-
retrievalStatus: "unknown" | "
|
|
6534
|
-
citationBasis: "
|
|
6533
|
+
retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
|
|
6534
|
+
citationBasis: "answer-support" | "explicit-citation" | "mixed" | "none";
|
|
6535
6535
|
citationMeasurable: boolean;
|
|
6536
6536
|
directSourceUrls: boolean;
|
|
6537
6537
|
location: {
|
|
@@ -6945,7 +6945,7 @@ declare const providerBatches: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
6945
6945
|
tableName: "provider_batches";
|
|
6946
6946
|
dataType: "string";
|
|
6947
6947
|
columnType: "SQLiteText";
|
|
6948
|
-
data: "unknown" | "failed" | "
|
|
6948
|
+
data: "unknown" | "failed" | "submitting" | "submitted" | "ended" | "ingested" | "cancelled";
|
|
6949
6949
|
driverParam: string;
|
|
6950
6950
|
notNull: true;
|
|
6951
6951
|
hasDefault: false;
|
|
@@ -6958,7 +6958,7 @@ declare const providerBatches: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
6958
6958
|
generated: undefined;
|
|
6959
6959
|
}, {}, {
|
|
6960
6960
|
length: number | undefined;
|
|
6961
|
-
$type: "unknown" | "failed" | "
|
|
6961
|
+
$type: "unknown" | "failed" | "submitting" | "submitted" | "ended" | "ingested" | "cancelled";
|
|
6962
6962
|
}>;
|
|
6963
6963
|
requestCount: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
6964
6964
|
name: "request_count";
|
|
@@ -7404,7 +7404,7 @@ declare const providerBatchRequests: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
7404
7404
|
tableName: "provider_batch_requests";
|
|
7405
7405
|
dataType: "string";
|
|
7406
7406
|
columnType: "SQLiteText";
|
|
7407
|
-
data: "
|
|
7407
|
+
data: "recorded" | "errored" | "expired" | "canceled" | "parse_failed" | "duplicate";
|
|
7408
7408
|
driverParam: string;
|
|
7409
7409
|
notNull: false;
|
|
7410
7410
|
hasDefault: false;
|
|
@@ -7417,7 +7417,7 @@ declare const providerBatchRequests: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
7417
7417
|
generated: undefined;
|
|
7418
7418
|
}, {}, {
|
|
7419
7419
|
length: number | undefined;
|
|
7420
|
-
$type: "
|
|
7420
|
+
$type: "recorded" | "errored" | "expired" | "canceled" | "parse_failed" | "duplicate";
|
|
7421
7421
|
}>;
|
|
7422
7422
|
error: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
7423
7423
|
name: "error";
|
|
@@ -9005,7 +9005,7 @@ declare const oauthTokens: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
9005
9005
|
tableName: "oauth_tokens";
|
|
9006
9006
|
dataType: "string";
|
|
9007
9007
|
columnType: "SQLiteText";
|
|
9008
|
-
data: "
|
|
9008
|
+
data: "access" | "refresh";
|
|
9009
9009
|
driverParam: string;
|
|
9010
9010
|
notNull: true;
|
|
9011
9011
|
hasDefault: false;
|
|
@@ -9018,7 +9018,7 @@ declare const oauthTokens: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
9018
9018
|
generated: undefined;
|
|
9019
9019
|
}, {}, {
|
|
9020
9020
|
length: number | undefined;
|
|
9021
|
-
$type: "
|
|
9021
|
+
$type: "access" | "refresh";
|
|
9022
9022
|
}>;
|
|
9023
9023
|
clientId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
9024
9024
|
name: "client_id";
|
|
@@ -12060,7 +12060,7 @@ declare const siteAuditSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns
|
|
|
12060
12060
|
weight: number;
|
|
12061
12061
|
sharePct: number | null;
|
|
12062
12062
|
avgScore: number;
|
|
12063
|
-
status: "
|
|
12063
|
+
status: "partial" | "pass" | "fail";
|
|
12064
12064
|
pagesPassing: number;
|
|
12065
12065
|
pagesPartial: number;
|
|
12066
12066
|
pagesFailing: number;
|
|
@@ -12082,7 +12082,7 @@ declare const siteAuditSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns
|
|
|
12082
12082
|
weight: number;
|
|
12083
12083
|
sharePct: number | null;
|
|
12084
12084
|
avgScore: number;
|
|
12085
|
-
status: "
|
|
12085
|
+
status: "partial" | "pass" | "fail";
|
|
12086
12086
|
pagesPassing: number;
|
|
12087
12087
|
pagesPartial: number;
|
|
12088
12088
|
pagesFailing: number;
|
|
@@ -25299,7 +25299,7 @@ declare const discoverySessions: drizzle_orm_sqlite_core.SQLiteTableWithColumns<
|
|
|
25299
25299
|
data: {
|
|
25300
25300
|
domain: string;
|
|
25301
25301
|
hits: number;
|
|
25302
|
-
competitorType: "unknown" | "
|
|
25302
|
+
competitorType: "unknown" | "direct-competitor" | "ota-aggregator" | "editorial-media" | "other";
|
|
25303
25303
|
evaluator?: {
|
|
25304
25304
|
provider: string;
|
|
25305
25305
|
requestedModel: string;
|
|
@@ -25321,7 +25321,7 @@ declare const discoverySessions: drizzle_orm_sqlite_core.SQLiteTableWithColumns<
|
|
|
25321
25321
|
$type: {
|
|
25322
25322
|
domain: string;
|
|
25323
25323
|
hits: number;
|
|
25324
|
-
competitorType: "unknown" | "
|
|
25324
|
+
competitorType: "unknown" | "direct-competitor" | "ota-aggregator" | "editorial-media" | "other";
|
|
25325
25325
|
evaluator?: {
|
|
25326
25326
|
provider: string;
|
|
25327
25327
|
requestedModel: string;
|
|
@@ -25572,7 +25572,7 @@ declare const researchRuns: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
25572
25572
|
dataType: "json";
|
|
25573
25573
|
columnType: "SQLiteTextJson";
|
|
25574
25574
|
data: {
|
|
25575
|
-
kind: "
|
|
25575
|
+
kind: "market" | "property";
|
|
25576
25576
|
key: string;
|
|
25577
25577
|
label: string;
|
|
25578
25578
|
planRevision: number;
|
|
@@ -25589,7 +25589,7 @@ declare const researchRuns: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
25589
25589
|
generated: undefined;
|
|
25590
25590
|
}, {}, {
|
|
25591
25591
|
$type: {
|
|
25592
|
-
kind: "
|
|
25592
|
+
kind: "market" | "property";
|
|
25593
25593
|
key: string;
|
|
25594
25594
|
label: string;
|
|
25595
25595
|
planRevision: number;
|
|
@@ -25740,7 +25740,7 @@ declare const researchRuns: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
25740
25740
|
dataType: "json";
|
|
25741
25741
|
columnType: "SQLiteTextJson";
|
|
25742
25742
|
data: {
|
|
25743
|
-
kind: "
|
|
25743
|
+
kind: "api-key" | "user";
|
|
25744
25744
|
id: string;
|
|
25745
25745
|
name: string;
|
|
25746
25746
|
role: "admin" | "viewer" | null;
|
|
@@ -25758,7 +25758,7 @@ declare const researchRuns: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
25758
25758
|
generated: undefined;
|
|
25759
25759
|
}, {}, {
|
|
25760
25760
|
$type: {
|
|
25761
|
-
kind: "
|
|
25761
|
+
kind: "api-key" | "user";
|
|
25762
25762
|
id: string;
|
|
25763
25763
|
name: string;
|
|
25764
25764
|
role: "admin" | "viewer" | null;
|
|
@@ -26295,8 +26295,8 @@ declare const researchRunQueries: drizzle_orm_sqlite_core.SQLiteTableWithColumns
|
|
|
26295
26295
|
status?: string | null | undefined;
|
|
26296
26296
|
}[];
|
|
26297
26297
|
searchQueries: string[];
|
|
26298
|
-
retrievalStatus: "unknown" | "
|
|
26299
|
-
citationBasis: "
|
|
26298
|
+
retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
|
|
26299
|
+
citationBasis: "answer-support" | "explicit-citation" | "mixed" | "none";
|
|
26300
26300
|
citationMeasurable: boolean;
|
|
26301
26301
|
directSourceUrls: boolean;
|
|
26302
26302
|
location: {
|
|
@@ -26400,8 +26400,8 @@ declare const researchRunQueries: drizzle_orm_sqlite_core.SQLiteTableWithColumns
|
|
|
26400
26400
|
status?: string | null | undefined;
|
|
26401
26401
|
}[];
|
|
26402
26402
|
searchQueries: string[];
|
|
26403
|
-
retrievalStatus: "unknown" | "
|
|
26404
|
-
citationBasis: "
|
|
26403
|
+
retrievalStatus: "unknown" | "used" | "not-used" | "not-applicable";
|
|
26404
|
+
citationBasis: "answer-support" | "explicit-citation" | "mixed" | "none";
|
|
26405
26405
|
citationMeasurable: boolean;
|
|
26406
26406
|
directSourceUrls: boolean;
|
|
26407
26407
|
location: {
|
|
@@ -26782,7 +26782,7 @@ declare const domainClassifications: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
26782
26782
|
tableName: "domain_classifications";
|
|
26783
26783
|
dataType: "string";
|
|
26784
26784
|
columnType: "SQLiteText";
|
|
26785
|
-
data: "unknown" | "
|
|
26785
|
+
data: "unknown" | "direct-competitor" | "ota-aggregator" | "editorial-media" | "other";
|
|
26786
26786
|
driverParam: string;
|
|
26787
26787
|
notNull: true;
|
|
26788
26788
|
hasDefault: false;
|
|
@@ -26795,7 +26795,7 @@ declare const domainClassifications: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
26795
26795
|
generated: undefined;
|
|
26796
26796
|
}, {}, {
|
|
26797
26797
|
length: number | undefined;
|
|
26798
|
-
$type: "unknown" | "
|
|
26798
|
+
$type: "unknown" | "direct-competitor" | "ota-aggregator" | "editorial-media" | "other";
|
|
26799
26799
|
}>;
|
|
26800
26800
|
hits: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
26801
26801
|
name: "hits";
|
|
@@ -29384,7 +29384,7 @@ declare const gbpReviews: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
29384
29384
|
tableName: "gbp_reviews";
|
|
29385
29385
|
dataType: "string";
|
|
29386
29386
|
columnType: "SQLiteText";
|
|
29387
|
-
data: "
|
|
29387
|
+
data: "pending" | "none" | "sent" | "baseline" | "stale" | "skipped" | "suppressed";
|
|
29388
29388
|
driverParam: string;
|
|
29389
29389
|
notNull: true;
|
|
29390
29390
|
hasDefault: true;
|
|
@@ -29397,7 +29397,7 @@ declare const gbpReviews: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
29397
29397
|
generated: undefined;
|
|
29398
29398
|
}, {}, {
|
|
29399
29399
|
length: number | undefined;
|
|
29400
|
-
$type: "
|
|
29400
|
+
$type: "pending" | "none" | "sent" | "baseline" | "stale" | "skipped" | "suppressed";
|
|
29401
29401
|
}>;
|
|
29402
29402
|
alertStateAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
29403
29403
|
name: "alert_state_at";
|
|
@@ -29694,7 +29694,7 @@ declare const gbpReviewRatings: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
29694
29694
|
tableName: "gbp_review_ratings";
|
|
29695
29695
|
dataType: "string";
|
|
29696
29696
|
columnType: "SQLiteText";
|
|
29697
|
-
data: "
|
|
29697
|
+
data: "pending" | "none" | "sent" | "baseline" | "stale" | "skipped" | "suppressed";
|
|
29698
29698
|
driverParam: string;
|
|
29699
29699
|
notNull: true;
|
|
29700
29700
|
hasDefault: true;
|
|
@@ -29707,7 +29707,7 @@ declare const gbpReviewRatings: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
29707
29707
|
generated: undefined;
|
|
29708
29708
|
}, {}, {
|
|
29709
29709
|
length: number | undefined;
|
|
29710
|
-
$type: "
|
|
29710
|
+
$type: "pending" | "none" | "sent" | "baseline" | "stale" | "skipped" | "suppressed";
|
|
29711
29711
|
}>;
|
|
29712
29712
|
alertStateAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
29713
29713
|
name: "alert_state_at";
|
|
@@ -30953,7 +30953,7 @@ declare const adsOperationSteps: drizzle_orm_sqlite_core.SQLiteTableWithColumns<
|
|
|
30953
30953
|
tableName: "ads_operation_steps";
|
|
30954
30954
|
dataType: "string";
|
|
30955
30955
|
columnType: "SQLiteText";
|
|
30956
|
-
data: "unknown" | "
|
|
30956
|
+
data: "unknown" | "failed" | "pending" | "active" | "executing" | "rollback_executing" | "rolled_back" | "rollback_failed";
|
|
30957
30957
|
driverParam: string;
|
|
30958
30958
|
notNull: true;
|
|
30959
30959
|
hasDefault: false;
|
|
@@ -30966,7 +30966,7 @@ declare const adsOperationSteps: drizzle_orm_sqlite_core.SQLiteTableWithColumns<
|
|
|
30966
30966
|
generated: undefined;
|
|
30967
30967
|
}, {}, {
|
|
30968
30968
|
length: number | undefined;
|
|
30969
|
-
$type: "unknown" | "
|
|
30969
|
+
$type: "unknown" | "failed" | "pending" | "active" | "executing" | "rollback_executing" | "rolled_back" | "rollback_failed";
|
|
30970
30970
|
}>;
|
|
30971
30971
|
providerUpdatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
30972
30972
|
name: "provider_updated_at";
|
|
@@ -32273,7 +32273,7 @@ declare const googleAdsConnections: drizzle_orm_sqlite_core.SQLiteTableWithColum
|
|
|
32273
32273
|
tableName: "google_ads_connections";
|
|
32274
32274
|
dataType: "string";
|
|
32275
32275
|
columnType: "SQLiteText";
|
|
32276
|
-
data: "unknown" | "
|
|
32276
|
+
data: "unknown" | "canceled" | "enabled" | "suspended" | "closed" | "unspecified";
|
|
32277
32277
|
driverParam: string;
|
|
32278
32278
|
notNull: false;
|
|
32279
32279
|
hasDefault: false;
|
|
@@ -32286,7 +32286,7 @@ declare const googleAdsConnections: drizzle_orm_sqlite_core.SQLiteTableWithColum
|
|
|
32286
32286
|
generated: undefined;
|
|
32287
32287
|
}, {}, {
|
|
32288
32288
|
length: number | undefined;
|
|
32289
|
-
$type: "unknown" | "
|
|
32289
|
+
$type: "unknown" | "canceled" | "enabled" | "suspended" | "closed" | "unspecified";
|
|
32290
32290
|
}>;
|
|
32291
32291
|
scopes: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
32292
32292
|
name: "scopes";
|
|
@@ -33233,7 +33233,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33233
33233
|
hidden: boolean;
|
|
33234
33234
|
testAccount: boolean;
|
|
33235
33235
|
level: number;
|
|
33236
|
-
status: "unknown" | "
|
|
33236
|
+
status: "unknown" | "canceled" | "enabled" | "suspended" | "closed" | "unspecified";
|
|
33237
33237
|
}[];
|
|
33238
33238
|
totalAccessible: number;
|
|
33239
33239
|
truncated: boolean;
|
|
@@ -33253,7 +33253,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33253
33253
|
id: string;
|
|
33254
33254
|
resourceName: string;
|
|
33255
33255
|
name: string;
|
|
33256
|
-
status: "unknown" | "enabled" | "
|
|
33256
|
+
status: "unknown" | "enabled" | "paused" | "removed";
|
|
33257
33257
|
advertisingChannelType: string | null;
|
|
33258
33258
|
biddingStrategyType: string | null;
|
|
33259
33259
|
}[];
|
|
@@ -33261,7 +33261,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33261
33261
|
id: string;
|
|
33262
33262
|
resourceName: string;
|
|
33263
33263
|
name: string;
|
|
33264
|
-
status: "unknown" | "enabled" | "
|
|
33264
|
+
status: "unknown" | "enabled" | "hidden" | "removed";
|
|
33265
33265
|
category: string;
|
|
33266
33266
|
origin: string;
|
|
33267
33267
|
primaryForGoal: boolean;
|
|
@@ -33285,7 +33285,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33285
33285
|
}[];
|
|
33286
33286
|
campaignGoalConfigurations: {
|
|
33287
33287
|
campaignId: string;
|
|
33288
|
-
goalConfigLevel: "
|
|
33288
|
+
goalConfigLevel: "campaign" | "customer";
|
|
33289
33289
|
customGoalId: string | null;
|
|
33290
33290
|
}[];
|
|
33291
33291
|
campaignConversionGoalsComplete?: boolean | undefined;
|
|
@@ -33336,7 +33336,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33336
33336
|
hidden: boolean;
|
|
33337
33337
|
testAccount: boolean;
|
|
33338
33338
|
level: number;
|
|
33339
|
-
status: "unknown" | "
|
|
33339
|
+
status: "unknown" | "canceled" | "enabled" | "suspended" | "closed" | "unspecified";
|
|
33340
33340
|
}[];
|
|
33341
33341
|
totalAccessible: number;
|
|
33342
33342
|
truncated: boolean;
|
|
@@ -33356,7 +33356,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33356
33356
|
id: string;
|
|
33357
33357
|
resourceName: string;
|
|
33358
33358
|
name: string;
|
|
33359
|
-
status: "unknown" | "enabled" | "
|
|
33359
|
+
status: "unknown" | "enabled" | "paused" | "removed";
|
|
33360
33360
|
advertisingChannelType: string | null;
|
|
33361
33361
|
biddingStrategyType: string | null;
|
|
33362
33362
|
}[];
|
|
@@ -33364,7 +33364,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33364
33364
|
id: string;
|
|
33365
33365
|
resourceName: string;
|
|
33366
33366
|
name: string;
|
|
33367
|
-
status: "unknown" | "enabled" | "
|
|
33367
|
+
status: "unknown" | "enabled" | "hidden" | "removed";
|
|
33368
33368
|
category: string;
|
|
33369
33369
|
origin: string;
|
|
33370
33370
|
primaryForGoal: boolean;
|
|
@@ -33388,7 +33388,7 @@ declare const googleAdsRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColu
|
|
|
33388
33388
|
}[];
|
|
33389
33389
|
campaignGoalConfigurations: {
|
|
33390
33390
|
campaignId: string;
|
|
33391
|
-
goalConfigLevel: "
|
|
33391
|
+
goalConfigLevel: "campaign" | "customer";
|
|
33392
33392
|
customGoalId: string | null;
|
|
33393
33393
|
}[];
|
|
33394
33394
|
campaignConversionGoalsComplete?: boolean | undefined;
|
|
@@ -33545,7 +33545,7 @@ declare const gtmRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
33545
33545
|
tableName: "gtm_raw_snapshots";
|
|
33546
33546
|
dataType: "string";
|
|
33547
33547
|
columnType: "SQLiteText";
|
|
33548
|
-
data: "
|
|
33548
|
+
data: "accounts" | "container" | "live" | "draft";
|
|
33549
33549
|
driverParam: string;
|
|
33550
33550
|
notNull: true;
|
|
33551
33551
|
hasDefault: false;
|
|
@@ -33558,7 +33558,7 @@ declare const gtmRawSnapshots: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
33558
33558
|
generated: undefined;
|
|
33559
33559
|
}, {}, {
|
|
33560
33560
|
length: number | undefined;
|
|
33561
|
-
$type: "
|
|
33561
|
+
$type: "accounts" | "container" | "live" | "draft";
|
|
33562
33562
|
}>;
|
|
33563
33563
|
accountId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
33564
33564
|
name: "account_id";
|
|
@@ -37224,8 +37224,8 @@ type ClassificationConfig = z.infer<typeof classificationConfigSchema>;
|
|
|
37224
37224
|
declare const seoInstallConfigSchema: z.ZodObject<{
|
|
37225
37225
|
enabled: z.ZodBoolean;
|
|
37226
37226
|
fundingMode: z.ZodEnum<{
|
|
37227
|
-
"self-hosted": "self-hosted";
|
|
37228
37227
|
hosted: "hosted";
|
|
37228
|
+
"self-hosted": "self-hosted";
|
|
37229
37229
|
}>;
|
|
37230
37230
|
policy: z.ZodObject<{
|
|
37231
37231
|
maxRunCostMicros: z.ZodNumber;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonry/canonry",
|
|
3
|
-
"version": "7.68.
|
|
3
|
+
"version": "7.68.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
|
|
6
6
|
"keywords": [
|