@gscdump/contracts 1.0.3 → 1.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.
package/dist/v1/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { accountNextActions, accountStatuses, analyticsNextActions, analyticsStatuses, builderStateSchema, gscComparisonFilterSchema, gscdumpAnalysisBundleResponseSchema, gscdumpAnalysisPresetSchema, gscdumpAnalysisResponseSchema, gscdumpAvailableSiteSchema, gscdumpDataDetailResponseSchema, gscdumpDataResponseSchema, gscdumpIndexingDiagnosticsResponseSchema, gscdumpIndexingResponseSchema, gscdumpSiteRegistrationSchema, gscdumpSitemapChangesResponseSchema, gscdumpSitemapsResponseSchema, gscdumpUserRegistrationSchema, indexingNextActions, indexingStatuses, indexingUrlsResponseSchema, lifecycleErrorCodes, propertyNextActions, propertyStatuses, querySourceModes, registerPartnerSiteSchema, registerPartnerUserSchema, searchTypeSchema, sitemapNextActions, sitemapStatuses, updatePartnerUserTokensSchema } from "../_chunks/schemas.mjs";
1
+ import { accountNextActions, accountStatuses, analyticsNextActions, analyticsStatuses, builderStateSchema, gscComparisonFilterSchema, gscdumpAnalysisBundleResponseSchema, gscdumpAnalysisPresetSchema, gscdumpAnalysisResponseSchema, gscdumpAvailableSiteSchema, gscdumpCanonicalMismatchesResponseSchema, gscdumpDataDetailResponseSchema, gscdumpDataResponseSchema, gscdumpIndexingDiagnosticsResponseSchema, gscdumpIndexingResponseSchema, gscdumpKeywordSparklinesResponseSchema, gscdumpPageTrendResponseSchema, gscdumpQueryTrendResponseSchema, gscdumpSiteRegistrationSchema, gscdumpSitemapChangesResponseSchema, gscdumpSitemapsResponseSchema, gscdumpUserRegistrationSchema, indexingNextActions, indexingStatuses, indexingUrlsResponseSchema, lifecycleErrorCodes, propertyNextActions, propertyStatuses, querySourceModes, registerPartnerSiteSchema, registerPartnerUserSchema, searchTypeSchema, sitemapNextActions, sitemapStatuses, updatePartnerUserTokensSchema } from "../_chunks/schemas.mjs";
2
2
  import { z } from "zod";
3
3
  const HTTP_V1_SURFACES = [
4
4
  "partner",
@@ -980,6 +980,76 @@ function createGscdumpV1Protocol() {
980
980
  updated: z.boolean(),
981
981
  sites: z.array(gscdumpAvailableSiteSchema)
982
982
  }), partnerResponseMeta);
983
+ const calendarDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD");
984
+ const trendQuery = z.strictObject({
985
+ startDate: calendarDate,
986
+ endDate: calendarDate,
987
+ searchType: searchTypeSchema.optional(),
988
+ prevStartDate: calendarDate.optional(),
989
+ prevEndDate: calendarDate.optional()
990
+ });
991
+ const keywordSparklinesRequest = z.strictObject({
992
+ keywords: z.array(z.string().trim().min(1)).min(1).max(20),
993
+ startDate: calendarDate,
994
+ endDate: calendarDate,
995
+ searchType: searchTypeSchema.optional()
996
+ });
997
+ const indexingInspectRequest = z.strictObject({ urls: z.array(z.string().url()).min(1).max(10) });
998
+ const canonicalMismatchesResponse = defineSuccessResponse(defineResponseObject(gscdumpCanonicalMismatchesResponseSchema.shape), partnerResponseMeta);
999
+ const keywordSparklinesResponse = defineSuccessResponse(defineResponseObject(gscdumpKeywordSparklinesResponseSchema.shape), partnerResponseMeta);
1000
+ const queryTrendResponse = defineSuccessResponse(defineResponseObject(gscdumpQueryTrendResponseSchema.shape), partnerResponseMeta);
1001
+ const pageTrendResponse = defineSuccessResponse(defineResponseObject(gscdumpPageTrendResponseSchema.shape), partnerResponseMeta);
1002
+ const permissionRecoveryResponse = defineSuccessResponse(defineResponseObject({
1003
+ success: z.boolean(),
1004
+ permissionLevel: z.string().nullable(),
1005
+ jobsQueued: z.number().int().nonnegative(),
1006
+ message: z.string().min(1)
1007
+ }), partnerResponseMeta);
1008
+ const inspectionFact = z.string().nullable();
1009
+ const inspectionResult = z.object({
1010
+ url: z.string(),
1011
+ verdict: inspectionFact,
1012
+ coverageState: inspectionFact,
1013
+ indexingState: inspectionFact,
1014
+ robotsTxtState: inspectionFact,
1015
+ pageFetchState: inspectionFact,
1016
+ lastCrawlTime: inspectionFact,
1017
+ crawlingUserAgent: inspectionFact,
1018
+ userCanonical: inspectionFact,
1019
+ googleCanonical: inspectionFact,
1020
+ sitemaps: inspectionFact,
1021
+ referringUrls: inspectionFact,
1022
+ mobileVerdict: inspectionFact,
1023
+ mobileIssues: inspectionFact,
1024
+ richResultsVerdict: inspectionFact,
1025
+ richResultsItems: inspectionFact,
1026
+ ampVerdict: inspectionFact,
1027
+ ampUrl: inspectionFact,
1028
+ ampIndexingState: inspectionFact,
1029
+ ampIndexStatusVerdict: inspectionFact,
1030
+ ampRobotsTxtState: inspectionFact,
1031
+ ampPageFetchState: inspectionFact,
1032
+ ampLastCrawlTime: inspectionFact,
1033
+ ampIssues: inspectionFact,
1034
+ inspectionResultLink: inspectionFact
1035
+ });
1036
+ const indexingInspectionResponse = defineSuccessResponse(defineResponseObject({
1037
+ siteId: realtimeSchemas.publicSiteId,
1038
+ rateLimit: z.strictObject({
1039
+ reserved: z.number().int().nonnegative(),
1040
+ remaining: z.number().int().nonnegative(),
1041
+ limit: z.number().int().positive()
1042
+ }),
1043
+ results: z.array(inspectionResult),
1044
+ errors: z.array(z.strictObject({
1045
+ url: z.string(),
1046
+ error: z.string()
1047
+ })),
1048
+ skipped: z.array(z.strictObject({
1049
+ url: z.string(),
1050
+ reason: z.enum(["domain_mismatch", "rate_limited"])
1051
+ }))
1052
+ }), partnerResponseMeta);
983
1053
  const responseStreamHead = defineResponseObject({
984
1054
  streamId: realtimeSchemas.streamId,
985
1055
  sequence: realtimeSchemas.sequence
@@ -1962,6 +2032,421 @@ function createGscdumpV1Protocol() {
1962
2032
  }
1963
2033
  }
1964
2034
  }
2035
+ }),
2036
+ getCanonicalMismatches: defineHttpOperation({
2037
+ id: "partner.sites.canonical.mismatches.get",
2038
+ method: "GET",
2039
+ path: "/sites/{siteId}/canonical-mismatches",
2040
+ visibility: "public",
2041
+ semantics: {
2042
+ kind: "query",
2043
+ sideEffects: "none",
2044
+ idempotent: true,
2045
+ retry: "idempotent",
2046
+ readConsistency: "primary"
2047
+ },
2048
+ auth: {
2049
+ credentials: ["user_key", "partner_key"],
2050
+ scopes: ["indexing:read"],
2051
+ ownership: [{
2052
+ credential: "user_key",
2053
+ rule: "authorized_site"
2054
+ }, {
2055
+ credential: "partner_key",
2056
+ rule: "authorized_site"
2057
+ }]
2058
+ },
2059
+ request: {
2060
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2061
+ query: null,
2062
+ headers: requestHeaders,
2063
+ body: null
2064
+ },
2065
+ responses: { 200: canonicalMismatchesResponse },
2066
+ errors: partnerSiteErrors,
2067
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
2068
+ resources: {
2069
+ reads: [{
2070
+ type: "site.indexing",
2071
+ idFrom: "params.siteId"
2072
+ }],
2073
+ changes: []
2074
+ },
2075
+ lifecycle: { introduced: "1.1.0" },
2076
+ docs: {
2077
+ summary: "List canonical mismatches",
2078
+ description: "Returns sitemap-scoped URLs whose Google-chosen canonical diverges from the declared canonical, with consolidation targets and trend.",
2079
+ tags: ["Indexing"],
2080
+ examples: {
2081
+ request: { params: { siteId: "s_01" } },
2082
+ response: {
2083
+ data: {
2084
+ mismatches: [],
2085
+ totalCount: 0,
2086
+ consolidationTargets: [],
2087
+ trend: [],
2088
+ meta: {
2089
+ siteUrl: "sc-domain:example.com",
2090
+ syncStatus: "synced"
2091
+ }
2092
+ },
2093
+ meta: {
2094
+ requestId: "req_01",
2095
+ surface: "partner",
2096
+ version: "1.0"
2097
+ }
2098
+ }
2099
+ }
2100
+ }
2101
+ }),
2102
+ inspectSiteUrls: defineHttpOperation({
2103
+ id: "partner.sites.indexing.inspect.create",
2104
+ method: "POST",
2105
+ path: "/sites/{siteId}/indexing/inspect",
2106
+ visibility: "public",
2107
+ semantics: {
2108
+ kind: "mutation",
2109
+ sideEffects: "state",
2110
+ idempotent: false,
2111
+ retry: "never",
2112
+ readConsistency: null
2113
+ },
2114
+ auth: {
2115
+ credentials: ["user_key", "partner_key"],
2116
+ scopes: ["indexing:write"],
2117
+ ownership: [{
2118
+ credential: "user_key",
2119
+ rule: "authorized_site"
2120
+ }, {
2121
+ credential: "partner_key",
2122
+ rule: "authorized_site"
2123
+ }]
2124
+ },
2125
+ request: {
2126
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2127
+ query: null,
2128
+ headers: requestHeaders,
2129
+ body: indexingInspectRequest
2130
+ },
2131
+ responses: { 200: indexingInspectionResponse },
2132
+ errors: partnerSiteErrors,
2133
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
2134
+ resources: {
2135
+ reads: [{
2136
+ type: "site.indexing",
2137
+ idFrom: "params.siteId"
2138
+ }],
2139
+ changes: [{
2140
+ type: "site.indexing",
2141
+ idFrom: "params.siteId"
2142
+ }]
2143
+ },
2144
+ lifecycle: { introduced: "1.1.0" },
2145
+ docs: {
2146
+ summary: "Inspect URLs on demand",
2147
+ description: "Runs live URL inspections against the daily per-site quota; URLs outside the site domain and over-quota URLs are reported as skipped. Exhausted quota fails with rate_limited.",
2148
+ tags: ["Indexing"],
2149
+ examples: {
2150
+ request: {
2151
+ params: { siteId: "s_01" },
2152
+ body: { urls: ["https://example.com/"] }
2153
+ },
2154
+ response: {
2155
+ data: {
2156
+ siteId: "s_01",
2157
+ rateLimit: {
2158
+ reserved: 1,
2159
+ remaining: 199,
2160
+ limit: 200
2161
+ },
2162
+ results: [],
2163
+ errors: [],
2164
+ skipped: []
2165
+ },
2166
+ meta: {
2167
+ requestId: "req_01",
2168
+ surface: "partner",
2169
+ version: "1.0"
2170
+ }
2171
+ }
2172
+ }
2173
+ }
2174
+ }),
2175
+ recoverSitePermission: defineHttpOperation({
2176
+ id: "partner.sites.permission.recover",
2177
+ method: "POST",
2178
+ path: "/sites/{siteId}/permission/recover",
2179
+ visibility: "public",
2180
+ semantics: {
2181
+ kind: "mutation",
2182
+ sideEffects: "state",
2183
+ idempotent: true,
2184
+ retry: "idempotent",
2185
+ readConsistency: null
2186
+ },
2187
+ auth: {
2188
+ credentials: ["user_key", "partner_key"],
2189
+ scopes: ["sites:write"],
2190
+ ownership: [{
2191
+ credential: "user_key",
2192
+ rule: "authorized_site"
2193
+ }, {
2194
+ credential: "partner_key",
2195
+ rule: "authorized_site"
2196
+ }]
2197
+ },
2198
+ request: {
2199
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2200
+ query: null,
2201
+ headers: requestHeaders,
2202
+ body: null
2203
+ },
2204
+ responses: { 200: permissionRecoveryResponse },
2205
+ errors: partnerSiteErrors,
2206
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
2207
+ resources: {
2208
+ reads: [{
2209
+ type: "site.auth",
2210
+ idFrom: "params.siteId"
2211
+ }],
2212
+ changes: [{
2213
+ type: "site.auth",
2214
+ idFrom: "params.siteId"
2215
+ }, {
2216
+ type: "site.lifecycle",
2217
+ idFrom: "params.siteId"
2218
+ }]
2219
+ },
2220
+ lifecycle: { introduced: "1.1.0" },
2221
+ docs: {
2222
+ summary: "Re-check and recover site permission",
2223
+ description: "Force-rechecks Google Search Console access for a permission-lost site; on recovery resets sync state and queues fresh sync jobs.",
2224
+ tags: ["Sites"],
2225
+ examples: {
2226
+ request: { params: { siteId: "s_01" } },
2227
+ response: {
2228
+ data: {
2229
+ success: true,
2230
+ permissionLevel: "siteFullUser",
2231
+ jobsQueued: 3,
2232
+ message: "Permission restored (siteFullUser). Queued 3 sync jobs."
2233
+ },
2234
+ meta: {
2235
+ requestId: "req_01",
2236
+ surface: "partner",
2237
+ version: "1.0"
2238
+ }
2239
+ }
2240
+ }
2241
+ }
2242
+ }),
2243
+ queryKeywordSparklines: defineHttpOperation({
2244
+ id: "partner.sites.keyword.sparklines.query",
2245
+ method: "POST",
2246
+ path: "/sites/{siteId}/keyword-sparklines",
2247
+ visibility: "public",
2248
+ semantics: {
2249
+ kind: "query",
2250
+ sideEffects: "none",
2251
+ idempotent: true,
2252
+ retry: "idempotent",
2253
+ readConsistency: "primary"
2254
+ },
2255
+ auth: {
2256
+ credentials: ["user_key", "partner_key"],
2257
+ scopes: ["analytics:read"],
2258
+ ownership: [{
2259
+ credential: "user_key",
2260
+ rule: "authorized_site"
2261
+ }, {
2262
+ credential: "partner_key",
2263
+ rule: "authorized_site"
2264
+ }]
2265
+ },
2266
+ request: {
2267
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2268
+ query: null,
2269
+ headers: requestHeaders,
2270
+ body: keywordSparklinesRequest
2271
+ },
2272
+ responses: { 200: keywordSparklinesResponse },
2273
+ errors: partnerSiteErrors,
2274
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
2275
+ resources: {
2276
+ reads: [{
2277
+ type: "site.analytics",
2278
+ idFrom: "params.siteId"
2279
+ }],
2280
+ changes: []
2281
+ },
2282
+ lifecycle: { introduced: "1.1.0" },
2283
+ docs: {
2284
+ summary: "Query keyword sparklines",
2285
+ description: "Returns per-keyword daily click series for up to 20 keywords over the requested window.",
2286
+ tags: ["Analytics"],
2287
+ examples: {
2288
+ request: {
2289
+ params: { siteId: "s_01" },
2290
+ body: {
2291
+ keywords: ["nuxt seo"],
2292
+ startDate: "2026-06-01",
2293
+ endDate: "2026-06-28"
2294
+ }
2295
+ },
2296
+ response: {
2297
+ data: { sparklines: { "nuxt seo": [
2298
+ 0,
2299
+ 1,
2300
+ 2
2301
+ ] } },
2302
+ meta: {
2303
+ requestId: "req_01",
2304
+ surface: "partner",
2305
+ version: "1.0"
2306
+ }
2307
+ }
2308
+ }
2309
+ }
2310
+ }),
2311
+ getQueryTrend: defineHttpOperation({
2312
+ id: "partner.sites.query.trend.get",
2313
+ method: "GET",
2314
+ path: "/sites/{siteId}/query-trend",
2315
+ visibility: "public",
2316
+ semantics: {
2317
+ kind: "query",
2318
+ sideEffects: "none",
2319
+ idempotent: true,
2320
+ retry: "idempotent",
2321
+ readConsistency: "primary"
2322
+ },
2323
+ auth: {
2324
+ credentials: ["user_key", "partner_key"],
2325
+ scopes: ["analytics:read"],
2326
+ ownership: [{
2327
+ credential: "user_key",
2328
+ rule: "authorized_site"
2329
+ }, {
2330
+ credential: "partner_key",
2331
+ rule: "authorized_site"
2332
+ }]
2333
+ },
2334
+ request: {
2335
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2336
+ query: trendQuery,
2337
+ headers: requestHeaders,
2338
+ body: null
2339
+ },
2340
+ responses: { 200: queryTrendResponse },
2341
+ errors: partnerSiteErrors,
2342
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
2343
+ resources: {
2344
+ reads: [{
2345
+ type: "site.analytics",
2346
+ idFrom: "params.siteId"
2347
+ }],
2348
+ changes: []
2349
+ },
2350
+ lifecycle: { introduced: "1.1.0" },
2351
+ docs: {
2352
+ summary: "Get unique-query trend",
2353
+ description: "Returns the daily unique-query count series for a window, with an optional previous-period total for comparison.",
2354
+ tags: ["Analytics"],
2355
+ examples: {
2356
+ request: {
2357
+ params: { siteId: "s_01" },
2358
+ query: {
2359
+ startDate: "2026-06-01",
2360
+ endDate: "2026-06-28"
2361
+ }
2362
+ },
2363
+ response: {
2364
+ data: {
2365
+ daily: [],
2366
+ total: 0,
2367
+ meta: {
2368
+ siteUrl: "sc-domain:example.com",
2369
+ syncStatus: "synced"
2370
+ }
2371
+ },
2372
+ meta: {
2373
+ requestId: "req_01",
2374
+ surface: "partner",
2375
+ version: "1.0"
2376
+ }
2377
+ }
2378
+ }
2379
+ }
2380
+ }),
2381
+ getPageTrend: defineHttpOperation({
2382
+ id: "partner.sites.page.trend.get",
2383
+ method: "GET",
2384
+ path: "/sites/{siteId}/page-trend",
2385
+ visibility: "public",
2386
+ semantics: {
2387
+ kind: "query",
2388
+ sideEffects: "none",
2389
+ idempotent: true,
2390
+ retry: "idempotent",
2391
+ readConsistency: "primary"
2392
+ },
2393
+ auth: {
2394
+ credentials: ["user_key", "partner_key"],
2395
+ scopes: ["analytics:read"],
2396
+ ownership: [{
2397
+ credential: "user_key",
2398
+ rule: "authorized_site"
2399
+ }, {
2400
+ credential: "partner_key",
2401
+ rule: "authorized_site"
2402
+ }]
2403
+ },
2404
+ request: {
2405
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2406
+ query: trendQuery,
2407
+ headers: requestHeaders,
2408
+ body: null
2409
+ },
2410
+ responses: { 200: pageTrendResponse },
2411
+ errors: partnerSiteErrors,
2412
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
2413
+ resources: {
2414
+ reads: [{
2415
+ type: "site.analytics",
2416
+ idFrom: "params.siteId"
2417
+ }],
2418
+ changes: []
2419
+ },
2420
+ lifecycle: { introduced: "1.1.0" },
2421
+ docs: {
2422
+ summary: "Get unique-page trend",
2423
+ description: "Returns the daily unique-page count series for a window, with an optional previous-period total for comparison.",
2424
+ tags: ["Analytics"],
2425
+ examples: {
2426
+ request: {
2427
+ params: { siteId: "s_01" },
2428
+ query: {
2429
+ startDate: "2026-06-01",
2430
+ endDate: "2026-06-28"
2431
+ }
2432
+ },
2433
+ response: {
2434
+ data: {
2435
+ daily: [],
2436
+ total: 0,
2437
+ meta: {
2438
+ siteUrl: "sc-domain:example.com",
2439
+ syncStatus: "synced"
2440
+ }
2441
+ },
2442
+ meta: {
2443
+ requestId: "req_01",
2444
+ surface: "partner",
2445
+ version: "1.0"
2446
+ }
2447
+ }
2448
+ }
2449
+ }
1965
2450
  })
1966
2451
  }
1967
2452
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/contracts",
3
3
  "type": "module",
4
- "version": "1.0.3",
4
+ "version": "1.1.0",
5
5
  "description": "Shared gscdump.com API, webhook, realtime, and lifecycle contracts.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",