@nuxtseo/protocol 0.1.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.
Files changed (44) hide show
  1. package/dist/analytics-codecs/analytics-row.d.ts +265 -0
  2. package/dist/analytics-codecs/analytics-row.js +175 -0
  3. package/dist/analytics-codecs/analytics-web-vitals.d.ts +57 -0
  4. package/dist/analytics-codecs/analytics-web-vitals.js +76 -0
  5. package/dist/analytics-codecs/capabilities.d.ts +35 -0
  6. package/dist/analytics-codecs/capabilities.js +76 -0
  7. package/dist/analytics-codecs/index.d.ts +3 -0
  8. package/dist/analytics-codecs/index.js +3 -0
  9. package/dist/cli-pairing.d.ts +67 -0
  10. package/dist/cli-pairing.js +52 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +1 -0
  13. package/dist/v1/account.d.ts +715 -0
  14. package/dist/v1/account.js +123 -0
  15. package/dist/v1/actions.d.ts +2591 -0
  16. package/dist/v1/actions.js +460 -0
  17. package/dist/v1/analytics.d.ts +6145 -0
  18. package/dist/v1/analytics.js +296 -0
  19. package/dist/v1/audit.d.ts +4053 -0
  20. package/dist/v1/audit.js +609 -0
  21. package/dist/v1/backlinks.d.ts +1002 -0
  22. package/dist/v1/backlinks.js +239 -0
  23. package/dist/v1/content.d.ts +2745 -0
  24. package/dist/v1/content.js +326 -0
  25. package/dist/v1/core.d.ts +301 -0
  26. package/dist/v1/core.js +333 -0
  27. package/dist/v1/documents.d.ts +4 -0
  28. package/dist/v1/documents.js +216 -0
  29. package/dist/v1/gsc.d.ts +5172 -0
  30. package/dist/v1/gsc.js +583 -0
  31. package/dist/v1/index.d.ts +49 -0
  32. package/dist/v1/index.js +52 -0
  33. package/dist/v1/pages.d.ts +1404 -0
  34. package/dist/v1/pages.js +287 -0
  35. package/dist/v1/performance.d.ts +1379 -0
  36. package/dist/v1/performance.js +198 -0
  37. package/dist/v1/research.d.ts +1173 -0
  38. package/dist/v1/research.js +174 -0
  39. package/dist/v1/sitemaps.d.ts +1506 -0
  40. package/dist/v1/sitemaps.js +199 -0
  41. package/dist/v1/sites.d.ts +591 -0
  42. package/dist/v1/sites.js +101 -0
  43. package/generated/openapi.v1.json +1 -0
  44. package/package.json +131 -0
package/dist/v1/gsc.js ADDED
@@ -0,0 +1,583 @@
1
+ import { canonicalDifferenceKindSchema, gscdumpAnalysisPresetSchema, gscdumpIndexingTransitionFieldSchema, gscdumpTotalsSchema, indexingIssueSchema, } from '@gscdump/contracts';
2
+ import { z as schema } from 'zod';
3
+ import { defineOperation, defineRegistry, defineResponseObject, defineSuccessEnvelope, publicV1ErrorEnvelope, publicV1StandardRatePolicy, } from './core.js';
4
+ export const searchConsoleSiteParamsSchema = schema.strictObject({
5
+ siteId: schema.string().min(1),
6
+ });
7
+ export const searchAnalyticsViewSchema = schema.enum([
8
+ 'pages',
9
+ 'keywords',
10
+ 'countries',
11
+ 'devices',
12
+ 'timeseries',
13
+ 'page-detail',
14
+ 'keyword-detail',
15
+ 'analysis',
16
+ ]);
17
+ const periodSchema = schema.enum(['7d', '28d', '3m', '6m', '12m']);
18
+ const pageUrlSchema = schema.string().refine(value => value.startsWith('/') || URL.canParse(value), 'Expected an absolute URL or a site-relative path starting with /.');
19
+ export const searchAnalyticsQuerySchema = schema.strictObject({
20
+ view: searchAnalyticsViewSchema,
21
+ period: periodSchema.default('28d'),
22
+ limit: schema.coerce.number().int().min(1).max(100).default(25),
23
+ page: schema.coerce.number().int().min(1).default(1),
24
+ search: schema.string().optional(),
25
+ sort: schema.enum(['clicks', 'impressions', 'ctr', 'position']).default('clicks'),
26
+ sortDir: schema.enum(['asc', 'desc']).default('desc'),
27
+ filter: schema.enum(['top-level', 'new', 'lost', 'improving', 'declining']).optional(),
28
+ pageUrl: pageUrlSchema.optional(),
29
+ keyword: schema.string().min(1).optional(),
30
+ preset: gscdumpAnalysisPresetSchema.optional(),
31
+ brandTerms: schema.string().optional(),
32
+ minClicks: schema.coerce.number().optional(),
33
+ maxClicks: schema.coerce.number().optional(),
34
+ minImpressions: schema.coerce.number().optional(),
35
+ maxImpressions: schema.coerce.number().optional(),
36
+ minPosition: schema.coerce.number().optional(),
37
+ maxPosition: schema.coerce.number().optional(),
38
+ maxCtr: schema.coerce.number().min(0).max(1).optional(),
39
+ }).superRefine((value, context) => {
40
+ if (value.view === 'page-detail' && !value.pageUrl)
41
+ context.addIssue({ code: 'custom', path: ['pageUrl'], message: 'pageUrl is required for page-detail.' });
42
+ if (value.view === 'keyword-detail' && !value.keyword)
43
+ context.addIssue({ code: 'custom', path: ['keyword'], message: 'keyword is required for keyword-detail.' });
44
+ if (value.view === 'analysis' && !value.preset)
45
+ context.addIssue({ code: 'custom', path: ['preset'], message: 'preset is required for analysis.' });
46
+ if (value.view === 'analysis'
47
+ && (value.preset === 'brand-only' || value.preset === 'non-brand')
48
+ && !value.brandTerms?.trim()) {
49
+ context.addIssue({ code: 'custom', path: ['brandTerms'], message: 'brandTerms is required for brand analysis.' });
50
+ }
51
+ });
52
+ const totalsSchema = defineResponseObject(gscdumpTotalsSchema.shape, gscdumpTotalsSchema.shape);
53
+ const representedTotalsSchema = defineResponseObject({ clicks: schema.number(), impressions: schema.number() }, { clicks: schema.number(), impressions: schema.number() });
54
+ const pageRowSchema = defineResponseObject({
55
+ url: schema.string().min(1),
56
+ clicks: schema.number(),
57
+ impressions: schema.number(),
58
+ ctr: schema.number(),
59
+ pos: schema.number(),
60
+ keyword: schema.string().nullable(),
61
+ prevClicks: schema.number().optional(),
62
+ prevPos: schema.number().optional(),
63
+ change: schema.number().nullable(),
64
+ });
65
+ const keywordRowSchema = defineResponseObject({
66
+ keyword: schema.string().min(1),
67
+ clicks: schema.number(),
68
+ impressions: schema.number(),
69
+ ctr: schema.number(),
70
+ pos: schema.number(),
71
+ topPage: schema.string().nullable(),
72
+ prevClicks: schema.number().optional(),
73
+ prevPos: schema.number().optional(),
74
+ change: schema.number().nullable(),
75
+ });
76
+ const countryRowSchema = defineResponseObject({
77
+ country: schema.string().min(1),
78
+ clicks: schema.number(),
79
+ impressions: schema.number(),
80
+ ctr: schema.number(),
81
+ pos: schema.number(),
82
+ prevClicks: schema.number().optional(),
83
+ change: schema.number().nullable(),
84
+ });
85
+ const deviceRowSchema = defineResponseObject({
86
+ device: schema.string().min(1),
87
+ clicks: schema.number(),
88
+ impressions: schema.number(),
89
+ ctr: schema.number(),
90
+ pos: schema.number(),
91
+ });
92
+ function breakdownSchema(view, row) {
93
+ return defineResponseObject({
94
+ site: schema.string().min(1),
95
+ type: schema.literal(view),
96
+ period: periodSchema,
97
+ total: schema.number().int().nonnegative(),
98
+ totals: totalsSchema.producer.nullable(),
99
+ totalsScope: schema.string().min(1),
100
+ representedTotals: representedTotalsSchema.producer,
101
+ representedTotalsScope: schema.string().min(1),
102
+ rows: schema.array(row.producer),
103
+ }, {
104
+ site: schema.string().min(1),
105
+ type: schema.literal(view),
106
+ period: periodSchema,
107
+ total: schema.number().int().nonnegative(),
108
+ totals: totalsSchema.client.nullable(),
109
+ totalsScope: schema.string().min(1),
110
+ representedTotals: representedTotalsSchema.client,
111
+ representedTotalsScope: schema.string().min(1),
112
+ rows: schema.array(row.client),
113
+ });
114
+ }
115
+ const pagesDataSchema = breakdownSchema('pages', pageRowSchema);
116
+ const keywordsDataSchema = breakdownSchema('keywords', keywordRowSchema);
117
+ const countriesDataSchema = breakdownSchema('countries', countryRowSchema);
118
+ const devicesDataSchema = breakdownSchema('devices', deviceRowSchema);
119
+ const dailyRowSchema = defineResponseObject({
120
+ date: schema.string().min(1),
121
+ clicks: schema.number(),
122
+ impressions: schema.number(),
123
+ ctr: schema.number(),
124
+ pos: schema.number(),
125
+ });
126
+ const timeseriesDataSchema = defineResponseObject({
127
+ site: schema.string().min(1),
128
+ type: schema.literal('timeseries'),
129
+ period: periodSchema,
130
+ totals: totalsSchema.producer.nullable(),
131
+ prevTotals: totalsSchema.producer.nullable(),
132
+ daily: schema.array(dailyRowSchema.producer),
133
+ }, {
134
+ site: schema.string().min(1),
135
+ type: schema.literal('timeseries'),
136
+ period: periodSchema,
137
+ totals: totalsSchema.client.nullable(),
138
+ prevTotals: totalsSchema.client.nullable(),
139
+ daily: schema.array(dailyRowSchema.client),
140
+ });
141
+ const pageDetailRowSchema = defineResponseObject({
142
+ keyword: schema.string().min(1),
143
+ clicks: schema.number(),
144
+ impressions: schema.number(),
145
+ ctr: schema.number(),
146
+ pos: schema.number(),
147
+ prevClicks: schema.number().optional(),
148
+ prevPos: schema.number().optional(),
149
+ });
150
+ const pageDetailDataSchema = defineResponseObject({
151
+ site: schema.string().min(1),
152
+ type: schema.literal('page-detail'),
153
+ pageUrl: pageUrlSchema,
154
+ period: periodSchema,
155
+ totals: totalsSchema.producer.nullable(),
156
+ rows: schema.array(pageDetailRowSchema.producer),
157
+ }, {
158
+ site: schema.string().min(1),
159
+ type: schema.literal('page-detail'),
160
+ pageUrl: pageUrlSchema,
161
+ period: periodSchema,
162
+ totals: totalsSchema.client.nullable(),
163
+ rows: schema.array(pageDetailRowSchema.client),
164
+ });
165
+ const keywordDetailRowSchema = defineResponseObject({
166
+ page: schema.string().min(1),
167
+ clicks: schema.number(),
168
+ impressions: schema.number(),
169
+ ctr: schema.number(),
170
+ pos: schema.number(),
171
+ prevClicks: schema.number().optional(),
172
+ prevPos: schema.number().optional(),
173
+ });
174
+ const keywordDetailDataSchema = defineResponseObject({
175
+ site: schema.string().min(1),
176
+ type: schema.literal('keyword-detail'),
177
+ keyword: schema.string().min(1),
178
+ period: periodSchema,
179
+ totals: totalsSchema.producer.nullable(),
180
+ rows: schema.array(keywordDetailRowSchema.producer),
181
+ }, {
182
+ site: schema.string().min(1),
183
+ type: schema.literal('keyword-detail'),
184
+ keyword: schema.string().min(1),
185
+ period: periodSchema,
186
+ totals: totalsSchema.client.nullable(),
187
+ rows: schema.array(keywordDetailRowSchema.client),
188
+ });
189
+ const analysisPrimitiveSchema = schema.union([schema.string(), schema.number(), schema.boolean(), schema.null()]);
190
+ const analysisRowSchema = defineResponseObject({
191
+ keyword: schema.string().min(1),
192
+ clicks: schema.number(),
193
+ impressions: schema.number(),
194
+ ctr: schema.number(),
195
+ pos: schema.number(),
196
+ page: schema.string().optional(),
197
+ prevClicks: schema.number().optional(),
198
+ prevPos: schema.number().optional(),
199
+ potentialClicks: schema.number().optional(),
200
+ opportunityScore: schema.number().optional(),
201
+ clicksChange: schema.number().optional(),
202
+ posChange: schema.number().optional(),
203
+ decayPct: schema.number().optional(),
204
+ missedClicks: schema.number().optional(),
205
+ });
206
+ const analysisDataSchema = defineResponseObject({
207
+ site: schema.string().min(1),
208
+ type: schema.literal('analysis'),
209
+ preset: gscdumpAnalysisPresetSchema,
210
+ description: schema.string().min(1),
211
+ criteria: schema.record(schema.string(), schema.union([schema.string(), schema.number(), schema.null()])),
212
+ period: periodSchema,
213
+ total: schema.number().int().nonnegative(),
214
+ summary: schema.record(schema.string(), analysisPrimitiveSchema).nullable(),
215
+ rows: schema.array(analysisRowSchema.producer),
216
+ }, {
217
+ site: schema.string().min(1),
218
+ type: schema.literal('analysis'),
219
+ preset: gscdumpAnalysisPresetSchema,
220
+ description: schema.string().min(1),
221
+ criteria: schema.record(schema.string(), schema.union([schema.string(), schema.number(), schema.null()])),
222
+ period: periodSchema,
223
+ total: schema.number().int().nonnegative(),
224
+ summary: schema.record(schema.string(), analysisPrimitiveSchema).nullable(),
225
+ rows: schema.array(analysisRowSchema.client),
226
+ });
227
+ export const searchAnalyticsDataSchema = {
228
+ producer: schema.discriminatedUnion('type', [
229
+ pagesDataSchema.producer,
230
+ keywordsDataSchema.producer,
231
+ countriesDataSchema.producer,
232
+ devicesDataSchema.producer,
233
+ timeseriesDataSchema.producer,
234
+ pageDetailDataSchema.producer,
235
+ keywordDetailDataSchema.producer,
236
+ analysisDataSchema.producer,
237
+ ]),
238
+ client: schema.discriminatedUnion('type', [
239
+ pagesDataSchema.client,
240
+ keywordsDataSchema.client,
241
+ countriesDataSchema.client,
242
+ devicesDataSchema.client,
243
+ timeseriesDataSchema.client,
244
+ pageDetailDataSchema.client,
245
+ keywordDetailDataSchema.client,
246
+ analysisDataSchema.client,
247
+ ]),
248
+ };
249
+ export const searchAnalyticsResponseSchema = defineSuccessEnvelope(searchAnalyticsDataSchema);
250
+ const searchStatusDataSchema = defineResponseObject({
251
+ site: schema.string().min(1),
252
+ connected: schema.literal(true),
253
+ syncStatus: schema.string().min(1),
254
+ progress: schema.strictObject({
255
+ percent: schema.number().min(0).max(100),
256
+ succeeded: schema.number().int().nonnegative(),
257
+ failed: schema.number().int().nonnegative(),
258
+ terminal: schema.number().int().nonnegative(),
259
+ pending: schema.number().int().nonnegative(),
260
+ total: schema.number().int().nonnegative(),
261
+ }),
262
+ dateRange: schema.strictObject({ oldest: schema.string().nullable(), newest: schema.string().nullable() }),
263
+ lastSyncAt: schema.string().datetime().nullable(),
264
+ isSyncing: schema.boolean(),
265
+ hasData: schema.boolean(),
266
+ completion: schema.strictObject({
267
+ jobsTerminal: schema.boolean(),
268
+ dateCoverageComplete: schema.boolean(),
269
+ missingDays: schema.number().int().nonnegative(),
270
+ }),
271
+ daysSynced: schema.number().int().nonnegative(),
272
+ daysAvailable: schema.number().int().nonnegative(),
273
+ }, {
274
+ site: schema.string().min(1),
275
+ connected: schema.literal(true),
276
+ syncStatus: schema.string().min(1),
277
+ progress: schema.looseObject({
278
+ percent: schema.number().min(0).max(100),
279
+ succeeded: schema.number().int().nonnegative(),
280
+ failed: schema.number().int().nonnegative(),
281
+ terminal: schema.number().int().nonnegative(),
282
+ pending: schema.number().int().nonnegative(),
283
+ total: schema.number().int().nonnegative(),
284
+ }),
285
+ dateRange: schema.looseObject({ oldest: schema.string().nullable(), newest: schema.string().nullable() }),
286
+ lastSyncAt: schema.string().datetime().nullable(),
287
+ isSyncing: schema.boolean(),
288
+ hasData: schema.boolean(),
289
+ completion: schema.looseObject({
290
+ jobsTerminal: schema.boolean(),
291
+ dateCoverageComplete: schema.boolean(),
292
+ missingDays: schema.number().int().nonnegative(),
293
+ }),
294
+ daysSynced: schema.number().int().nonnegative(),
295
+ daysAvailable: schema.number().int().nonnegative(),
296
+ });
297
+ export const searchStatusResponseSchema = defineSuccessEnvelope(searchStatusDataSchema);
298
+ export const indexingDiagnosticsQuerySchema = schema.strictObject({
299
+ view: schema.enum(['summary', 'urls']).default('summary'),
300
+ issue: schema.string().min(1).optional(),
301
+ status: schema.enum(['indexed', 'not_indexed', 'pending']).optional(),
302
+ limit: schema.coerce.number().int().min(1).max(500).default(50),
303
+ offset: schema.coerce.number().int().min(0).default(0),
304
+ });
305
+ const issueSchema = defineResponseObject(indexingIssueSchema.shape, indexingIssueSchema.shape);
306
+ const diagnosticsSummaryDataSchema = defineResponseObject({
307
+ view: schema.literal('summary'),
308
+ totalUrls: schema.number().int().nonnegative(),
309
+ indexed: schema.number().int().nonnegative(),
310
+ asOf: schema.string().datetime().nullable(),
311
+ issues: schema.array(issueSchema.producer),
312
+ }, {
313
+ view: schema.literal('summary'),
314
+ totalUrls: schema.number().int().nonnegative(),
315
+ indexed: schema.number().int().nonnegative(),
316
+ asOf: schema.string().datetime().nullable(),
317
+ issues: schema.array(issueSchema.client),
318
+ });
319
+ const diagnosticsUrlSchema = defineResponseObject({
320
+ url: schema.string().min(1),
321
+ verdict: schema.string().nullable(),
322
+ coverageState: schema.string().nullable(),
323
+ indexingState: schema.string().nullable(),
324
+ userCanonical: schema.string().nullable(),
325
+ googleCanonical: schema.string().nullable(),
326
+ lastCrawlTime: schema.string().nullable(),
327
+ lastCheckedAt: schema.string().datetime(),
328
+ });
329
+ const diagnosticsUrlsDataSchema = defineResponseObject({
330
+ view: schema.literal('urls'),
331
+ total: schema.number().int().nonnegative(),
332
+ limit: schema.number().int().positive(),
333
+ offset: schema.number().int().nonnegative(),
334
+ hasMore: schema.boolean(),
335
+ urls: schema.array(diagnosticsUrlSchema.producer),
336
+ }, {
337
+ view: schema.literal('urls'),
338
+ total: schema.number().int().nonnegative(),
339
+ limit: schema.number().int().positive(),
340
+ offset: schema.number().int().nonnegative(),
341
+ hasMore: schema.boolean(),
342
+ urls: schema.array(diagnosticsUrlSchema.client),
343
+ });
344
+ export const indexingDiagnosticsDataSchema = {
345
+ producer: schema.discriminatedUnion('view', [diagnosticsSummaryDataSchema.producer, diagnosticsUrlsDataSchema.producer]),
346
+ client: schema.discriminatedUnion('view', [diagnosticsSummaryDataSchema.client, diagnosticsUrlsDataSchema.client]),
347
+ };
348
+ export const indexingDiagnosticsResponseSchema = defineSuccessEnvelope(indexingDiagnosticsDataSchema);
349
+ export const indexingHistoryQuerySchema = schema.strictObject({
350
+ url: pageUrlSchema.optional(),
351
+ field: gscdumpIndexingTransitionFieldSchema.optional(),
352
+ days: schema.coerce.number().int().min(1).max(730).default(180),
353
+ });
354
+ const markerSchema = defineResponseObject({
355
+ day: schema.string().date(),
356
+ label: schema.string().min(1),
357
+ source: schema.enum(['release', 'annotation']),
358
+ });
359
+ const causeSchema = {
360
+ producer: schema.discriminatedUnion('_tag', [
361
+ schema.strictObject({ _tag: schema.literal('sole-candidate'), marker: markerSchema.producer }),
362
+ schema.strictObject({ _tag: schema.literal('ambiguous'), markers: schema.array(markerSchema.producer) }),
363
+ schema.strictObject({ _tag: schema.literal('no-known-change') }),
364
+ ]),
365
+ client: schema.discriminatedUnion('_tag', [
366
+ schema.looseObject({ _tag: schema.literal('sole-candidate'), marker: markerSchema.client }),
367
+ schema.looseObject({ _tag: schema.literal('ambiguous'), markers: schema.array(markerSchema.client) }),
368
+ schema.looseObject({ _tag: schema.literal('no-known-change') }),
369
+ ]),
370
+ };
371
+ const historyChangeSchema = defineResponseObject({
372
+ url: schema.string().min(1),
373
+ field: gscdumpIndexingTransitionFieldSchema,
374
+ fromValue: schema.string().nullable(),
375
+ toValue: schema.string().nullable(),
376
+ afterDay: schema.string().date(),
377
+ beforeDay: schema.string().date(),
378
+ observedOverDays: schema.number().int().nonnegative(),
379
+ cause: causeSchema.producer,
380
+ }, {
381
+ url: schema.string().min(1),
382
+ field: gscdumpIndexingTransitionFieldSchema,
383
+ fromValue: schema.string().nullable(),
384
+ toValue: schema.string().nullable(),
385
+ afterDay: schema.string().date(),
386
+ beforeDay: schema.string().date(),
387
+ observedOverDays: schema.number().int().nonnegative(),
388
+ cause: causeSchema.client,
389
+ });
390
+ const historyScopeSchema = {
391
+ producer: schema.discriminatedUnion('_tag', [
392
+ schema.strictObject({ _tag: schema.literal('url'), url: schema.string().min(1) }),
393
+ schema.strictObject({ _tag: schema.literal('site'), field: gscdumpIndexingTransitionFieldSchema }),
394
+ ]),
395
+ client: schema.discriminatedUnion('_tag', [
396
+ schema.looseObject({ _tag: schema.literal('url'), url: schema.string().min(1) }),
397
+ schema.looseObject({ _tag: schema.literal('site'), field: gscdumpIndexingTransitionFieldSchema }),
398
+ ]),
399
+ };
400
+ const unchangedSchema = defineResponseObject({
401
+ observations: schema.number().int().nonnegative().nullable(),
402
+ firstObservedDay: schema.string().date().nullable(),
403
+ lastObservedDay: schema.string().date().nullable(),
404
+ });
405
+ export const indexingHistoryDataSchema = defineResponseObject({
406
+ scope: historyScopeSchema.producer,
407
+ startDate: schema.string().date(),
408
+ endDate: schema.string().date(),
409
+ complete: schema.boolean(),
410
+ resolvedUrl: schema.string().nullable(),
411
+ unchanged: unchangedSchema.producer.nullable(),
412
+ changes: schema.array(historyChangeSchema.producer),
413
+ }, {
414
+ scope: historyScopeSchema.client,
415
+ startDate: schema.string().date(),
416
+ endDate: schema.string().date(),
417
+ complete: schema.boolean(),
418
+ resolvedUrl: schema.string().nullable(),
419
+ unchanged: unchangedSchema.client.nullable(),
420
+ changes: schema.array(historyChangeSchema.client),
421
+ });
422
+ export const indexingHistoryResponseSchema = defineSuccessEnvelope(indexingHistoryDataSchema);
423
+ export const urlInspectionQuerySchema = schema.strictObject({ url: pageUrlSchema });
424
+ const inspectedSchema = defineResponseObject({
425
+ _tag: schema.literal('inspected'),
426
+ requestedUrl: schema.string().min(1),
427
+ inspectedUrl: schema.string().min(1),
428
+ verdict: schema.string().nullable(),
429
+ coverageState: schema.string().nullable(),
430
+ indexingState: schema.string().nullable(),
431
+ robotsTxtState: schema.string().nullable(),
432
+ pageFetchState: schema.string().nullable(),
433
+ lastCrawlTime: schema.string().nullable(),
434
+ crawledAs: schema.string().nullable(),
435
+ userCanonical: schema.string().nullable(),
436
+ googleCanonical: schema.string().nullable(),
437
+ canonicalisedAway: schema.boolean(),
438
+ canonicalMismatchKind: canonicalDifferenceKindSchema,
439
+ sitemaps: schema.array(schema.string()),
440
+ referringUrls: schema.array(schema.string()),
441
+ inspectionResultLink: schema.string().nullable(),
442
+ lastCheckedAt: schema.string().datetime(),
443
+ firstCheckedAt: schema.string().datetime().nullable(),
444
+ checkCount: schema.number().int().nonnegative().nullable(),
445
+ });
446
+ const retainedEvidenceSchema = defineResponseObject({
447
+ _tag: schema.literal('retained-evidence'),
448
+ requestedUrl: schema.string().min(1),
449
+ evidenceUrl: schema.string().min(1),
450
+ issueType: schema.string().min(1),
451
+ label: schema.string().nullable(),
452
+ coverageState: schema.string().nullable(),
453
+ userCanonical: schema.string().nullable(),
454
+ googleCanonical: schema.string().nullable(),
455
+ canonicalisedAway: schema.boolean(),
456
+ observedAt: schema.string().datetime(),
457
+ lastSeenAt: schema.string().datetime().nullable(),
458
+ });
459
+ const noInspectionDataSchema = defineResponseObject({
460
+ _tag: schema.literal('no-inspection-data'),
461
+ requestedUrl: schema.string().min(1),
462
+ });
463
+ export const urlInspectionDataSchema = {
464
+ producer: schema.discriminatedUnion('_tag', [inspectedSchema.producer, retainedEvidenceSchema.producer, noInspectionDataSchema.producer]),
465
+ client: schema.discriminatedUnion('_tag', [inspectedSchema.client, retainedEvidenceSchema.client, noInspectionDataSchema.client]),
466
+ };
467
+ export const urlInspectionResponseSchema = defineSuccessEnvelope(urlInspectionDataSchema);
468
+ const readErrors = [
469
+ 'invalid_request',
470
+ 'unauthorized',
471
+ 'auth_expired',
472
+ 'forbidden',
473
+ 'not_found',
474
+ 'entitlement_required',
475
+ 'stale_evidence',
476
+ 'rate_limited',
477
+ 'provider_unavailable',
478
+ 'conflict',
479
+ 'contract_violation',
480
+ 'internal_error',
481
+ ];
482
+ const common = {
483
+ visibility: 'public',
484
+ semantics: { kind: 'query', sideEffects: 'none', retry: 'idempotent', readConsistency: 'replica-ok' },
485
+ auth: {
486
+ credentials: ['session', 'api_token'],
487
+ scopes: ['sites:read'],
488
+ minimumRole: 'viewer',
489
+ ownership: 'site',
490
+ },
491
+ errors: readErrors,
492
+ errorResponse: publicV1ErrorEnvelope,
493
+ policy: { rate: publicV1StandardRatePolicy, idempotency: { _tag: 'none' }, entitlement: null, meter: null },
494
+ lifecycle: { introduced: '1.0.0' },
495
+ };
496
+ export const searchAnalyticsQueryOperation = defineOperation({
497
+ ...common,
498
+ id: 'sites.search.analytics.query',
499
+ method: 'GET',
500
+ path: '/api/v1/sites/{siteId}/search/analytics',
501
+ request: { params: searchConsoleSiteParamsSchema, query: searchAnalyticsQuerySchema, headers: null, body: null },
502
+ responses: { 200: searchAnalyticsResponseSchema },
503
+ resources: { reads: [{ type: 'site.analytics', idFrom: 'params.siteId' }], changes: [] },
504
+ docs: {
505
+ summary: 'Query Site search analytics',
506
+ description: 'Returns a bounded Search Console breakdown, trend, detail, or opportunity analysis for one NuxtSEO Site.',
507
+ tags: ['Sites', 'Search'],
508
+ examples: [{
509
+ request: { params: { siteId: 'site_01JXYZ' }, query: { view: 'keywords' } },
510
+ response: { status: 200, body: { data: { site: 'https://example.com', type: 'keywords', period: '28d', total: 1, totals: { clicks: 12, impressions: 100, ctr: 0.12, position: 4 }, totalsScope: 'full upstream query population', representedTotals: { clicks: 12, impressions: 100 }, representedTotalsScope: 'returned rows', rows: [{ keyword: 'nuxt seo', clicks: 12, impressions: 100, ctr: 0.12, pos: 4, topPage: 'https://example.com/docs', change: 2 }] }, meta: { requestId: 'req_01JXYZ', version: '1.0' } } },
511
+ }],
512
+ },
513
+ });
514
+ export const searchStatusReadOperation = defineOperation({
515
+ ...common,
516
+ id: 'sites.search.status.read',
517
+ method: 'GET',
518
+ path: '/api/v1/sites/{siteId}/search/status',
519
+ request: { params: searchConsoleSiteParamsSchema, query: null, headers: null, body: null },
520
+ responses: { 200: searchStatusResponseSchema },
521
+ resources: { reads: [{ type: 'site.identity', idFrom: 'params.siteId' }], changes: [] },
522
+ docs: {
523
+ summary: 'Read Site search status',
524
+ description: 'Returns aggregate Search Console synchronization reach for the credential authoritatively bound to the Site Team.',
525
+ tags: ['Sites', 'Search'],
526
+ examples: [{ request: { params: { siteId: 'site_01JXYZ' } }, response: { status: 200, body: { data: { site: 'https://example.com', connected: true, syncStatus: 'synced', progress: { percent: 100, succeeded: 4, failed: 0, terminal: 4, pending: 0, total: 4 }, dateRange: { oldest: '2026-01-01', newest: '2026-08-09' }, lastSyncAt: '2026-08-10T00:00:00.000Z', isSyncing: false, hasData: true, completion: { jobsTerminal: true, dateCoverageComplete: true, missingDays: 0 }, daysSynced: 221, daysAvailable: 221 }, meta: { requestId: 'req_01JXYZ', version: '1.0' } } } }],
527
+ },
528
+ });
529
+ export const indexingDiagnosticsReadOperation = defineOperation({
530
+ ...common,
531
+ id: 'sites.search.indexing.diagnostics.read',
532
+ method: 'GET',
533
+ path: '/api/v1/sites/{siteId}/search/indexing/diagnostics',
534
+ request: { params: searchConsoleSiteParamsSchema, query: indexingDiagnosticsQuerySchema, headers: null, body: null },
535
+ responses: { 200: indexingDiagnosticsResponseSchema },
536
+ resources: { reads: [{ type: 'site.page', idFrom: 'params.siteId' }], changes: [] },
537
+ docs: {
538
+ summary: 'Diagnose Site indexing',
539
+ description: 'Returns indexed coverage and issue counts, or one filtered page of affected URLs, from retained Search Console evidence.',
540
+ tags: ['Sites', 'Search', 'Indexing'],
541
+ examples: [{ request: { params: { siteId: 'site_01JXYZ' }, query: { view: 'summary' } }, response: { status: 200, body: { data: { view: 'summary', totalUrls: 100, indexed: 92, asOf: '2026-08-10T00:00:00.000Z', issues: [] }, meta: { requestId: 'req_01JXYZ', version: '1.0' } } } }],
542
+ },
543
+ });
544
+ export const indexingHistoryReadOperation = defineOperation({
545
+ ...common,
546
+ id: 'sites.search.indexing.history.read',
547
+ method: 'GET',
548
+ path: '/api/v1/sites/{siteId}/search/indexing/history',
549
+ request: { params: searchConsoleSiteParamsSchema, query: indexingHistoryQuerySchema, headers: null, body: null },
550
+ responses: { 200: indexingHistoryResponseSchema },
551
+ resources: { reads: [{ type: 'site.page', idFrom: 'params.siteId' }], changes: [] },
552
+ docs: {
553
+ summary: 'Read Site indexing history',
554
+ description: 'Returns retained indexing changes as observation windows, preserving uncertainty and candidate deploy correlation.',
555
+ tags: ['Sites', 'Search', 'Indexing'],
556
+ examples: [{ request: { params: { siteId: 'site_01JXYZ' }, query: { field: 'coverageState', days: 90 } }, response: { status: 200, body: { data: { scope: { _tag: 'site', field: 'coverageState' }, startDate: '2026-05-12', endDate: '2026-08-10', complete: true, resolvedUrl: null, unchanged: null, changes: [] }, meta: { requestId: 'req_01JXYZ', version: '1.0' } } } }],
557
+ },
558
+ });
559
+ export const urlInspectionReadOperation = defineOperation({
560
+ ...common,
561
+ id: 'sites.search.indexing.inspection.read',
562
+ method: 'GET',
563
+ path: '/api/v1/sites/{siteId}/search/indexing/inspection',
564
+ request: { params: searchConsoleSiteParamsSchema, query: urlInspectionQuerySchema, headers: null, body: null },
565
+ responses: { 200: urlInspectionResponseSchema },
566
+ resources: { reads: [{ type: 'site.page', idFrom: 'params.siteId' }], changes: [] },
567
+ docs: {
568
+ summary: 'Inspect one indexed URL',
569
+ description: 'Returns the latest retained URL Inspection result, dated local evidence, or an explicit no-data state for one Site URL.',
570
+ tags: ['Sites', 'Search', 'Indexing'],
571
+ examples: [{ request: { params: { siteId: 'site_01JXYZ' }, query: { url: '/docs' } }, response: { status: 200, body: { data: { _tag: 'no-inspection-data', requestedUrl: 'https://example.com/docs' }, meta: { requestId: 'req_01JXYZ', version: '1.0' } } } }],
572
+ },
573
+ });
574
+ export const searchV1Registry = defineRegistry({
575
+ feature: 'sites',
576
+ operations: {
577
+ queryAnalytics: searchAnalyticsQueryOperation,
578
+ readStatus: searchStatusReadOperation,
579
+ readIndexingDiagnostics: indexingDiagnosticsReadOperation,
580
+ readIndexingHistory: indexingHistoryReadOperation,
581
+ readUrlInspection: urlInspectionReadOperation,
582
+ },
583
+ });
@@ -0,0 +1,49 @@
1
+ import type { PublicV1ProtocolLike } from './core.js';
2
+ import { accountV1Registry } from './account.js';
3
+ import { actionsV1Registry } from './actions.js';
4
+ import { analyticsV1Registry } from './analytics.js';
5
+ import { auditV1Registry } from './audit.js';
6
+ import { backlinksV1Registry, mentionsV1Registry } from './backlinks.js';
7
+ import { contentV1Registry } from './content.js';
8
+ import { publicV1ErrorEnvelope } from './core.js';
9
+ import { searchV1Registry } from './gsc.js';
10
+ import { pagesV1Registry } from './pages.js';
11
+ import { performanceV1Registry } from './performance.js';
12
+ import { researchV1Registry } from './research.js';
13
+ import { sitemapsV1Registry } from './sitemaps.js';
14
+ import { sitesV1Registry } from './sites.js';
15
+ export * from './account.js';
16
+ export * from './actions.js';
17
+ export * from './analytics.js';
18
+ export * from './audit.js';
19
+ export * from './backlinks.js';
20
+ export * from './content.js';
21
+ export * from './core.js';
22
+ export * from './documents.js';
23
+ export * from './gsc.js';
24
+ export * from './pages.js';
25
+ export * from './performance.js';
26
+ export * from './research.js';
27
+ export * from './sitemaps.js';
28
+ export * from './sites.js';
29
+ export interface PublicV1Protocol extends Omit<PublicV1ProtocolLike, 'registries' | 'schemas'> {
30
+ registries: {
31
+ readonly account: typeof accountV1Registry;
32
+ readonly actions: typeof actionsV1Registry;
33
+ readonly analytics: typeof analyticsV1Registry;
34
+ readonly audit: typeof auditV1Registry;
35
+ readonly backlinks: typeof backlinksV1Registry;
36
+ readonly mentions: typeof mentionsV1Registry;
37
+ readonly content: typeof contentV1Registry;
38
+ readonly page: typeof pagesV1Registry;
39
+ readonly performance: typeof performanceV1Registry;
40
+ readonly research: typeof researchV1Registry;
41
+ readonly search: typeof searchV1Registry;
42
+ readonly sites: typeof sitesV1Registry;
43
+ readonly sitemaps: typeof sitemapsV1Registry;
44
+ };
45
+ schemas: {
46
+ readonly errorEnvelope: typeof publicV1ErrorEnvelope;
47
+ };
48
+ }
49
+ export declare function createPublicV1Protocol(): PublicV1Protocol;
@@ -0,0 +1,52 @@
1
+ import { accountV1Registry } from './account.js';
2
+ import { actionsV1Registry } from './actions.js';
3
+ import { analyticsV1Registry } from './analytics.js';
4
+ import { auditV1Registry } from './audit.js';
5
+ import { backlinksV1Registry, mentionsV1Registry } from './backlinks.js';
6
+ import { contentV1Registry } from './content.js';
7
+ import { defineProtocol, PUBLIC_V1_VERSION, publicV1ErrorEnvelope } from './core.js';
8
+ import { searchV1Registry } from './gsc.js';
9
+ import { pagesV1Registry } from './pages.js';
10
+ import { performanceV1Registry } from './performance.js';
11
+ import { researchV1Registry } from './research.js';
12
+ import { sitemapsV1Registry } from './sitemaps.js';
13
+ import { sitesV1Registry } from './sites.js';
14
+ export * from './account.js';
15
+ export * from './actions.js';
16
+ export * from './analytics.js';
17
+ export * from './audit.js';
18
+ export * from './backlinks.js';
19
+ export * from './content.js';
20
+ export * from './core.js';
21
+ export * from './documents.js';
22
+ export * from './gsc.js';
23
+ export * from './pages.js';
24
+ export * from './performance.js';
25
+ export * from './research.js';
26
+ export * from './sitemaps.js';
27
+ export * from './sites.js';
28
+ export function createPublicV1Protocol() {
29
+ const protocol = {
30
+ version: PUBLIC_V1_VERSION,
31
+ registries: {
32
+ account: accountV1Registry,
33
+ actions: actionsV1Registry,
34
+ analytics: analyticsV1Registry,
35
+ audit: auditV1Registry,
36
+ backlinks: backlinksV1Registry,
37
+ mentions: mentionsV1Registry,
38
+ content: contentV1Registry,
39
+ page: pagesV1Registry,
40
+ performance: performanceV1Registry,
41
+ research: researchV1Registry,
42
+ search: searchV1Registry,
43
+ sites: sitesV1Registry,
44
+ sitemaps: sitemapsV1Registry,
45
+ },
46
+ schemas: {
47
+ errorEnvelope: publicV1ErrorEnvelope,
48
+ },
49
+ };
50
+ defineProtocol(protocol);
51
+ return protocol;
52
+ }