@gscdump/contracts 0.11.4

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/index.mjs ADDED
@@ -0,0 +1,1486 @@
1
+ import { z } from "zod";
2
+ const partnerRoutes = {
3
+ partner: {
4
+ users: {
5
+ byId: (userId) => `/partner/users/${encodeURIComponent(userId)}`,
6
+ lifecycle: (userId) => `/partner/users/${encodeURIComponent(userId)}/lifecycle`,
7
+ siteTeam: (userId, siteId) => `/partner/users/${encodeURIComponent(userId)}/sites/${encodeURIComponent(siteId)}`
8
+ },
9
+ sites: {
10
+ register: "/partner/sites/register",
11
+ bulkRegister: "/partner/sites/bulk-register"
12
+ }
13
+ },
14
+ users: {
15
+ register: "/users/register",
16
+ tokens: (userId) => `/users/${encodeURIComponent(userId)}/tokens`,
17
+ status: (userId) => `/users/${encodeURIComponent(userId)}/status`,
18
+ lifecycle: (userId) => `/users/${encodeURIComponent(userId)}/lifecycle`,
19
+ sites: (userId) => `/users/${encodeURIComponent(userId)}/sites`,
20
+ availableSites: (userId) => `/users/${encodeURIComponent(userId)}/available-sites`,
21
+ siteTeam: (userId, siteId) => `/partner/users/${encodeURIComponent(userId)}/sites/${encodeURIComponent(siteId)}`
22
+ },
23
+ sites: {
24
+ register: "/sites/register",
25
+ bulkRegister: "/sites/bulk-register",
26
+ byId: (siteId) => `/sites/${encodeURIComponent(siteId)}`,
27
+ analysisSources: (siteId) => `/sites/${encodeURIComponent(siteId)}/analysis-sources`,
28
+ syncStatus: (siteId) => `/sites/${encodeURIComponent(siteId)}/sync-status`,
29
+ data: (siteId) => `/sites/${encodeURIComponent(siteId)}/data`,
30
+ dataDetail: (siteId) => `/sites/${encodeURIComponent(siteId)}/data/detail`,
31
+ analysis: (siteId) => `/sites/${encodeURIComponent(siteId)}/analysis`,
32
+ sitemaps: (siteId) => `/sites/${encodeURIComponent(siteId)}/sitemaps`,
33
+ sitemapChanges: (siteId) => `/sites/${encodeURIComponent(siteId)}/sitemaps/changes`,
34
+ indexing: (siteId) => `/sites/${encodeURIComponent(siteId)}/indexing`,
35
+ indexingUrls: (siteId) => `/sites/${encodeURIComponent(siteId)}/indexing/urls`,
36
+ indexingDiagnostics: (siteId) => `/sites/${encodeURIComponent(siteId)}/indexing/diagnostics`,
37
+ recoverPermission: (siteId) => `/sites/${encodeURIComponent(siteId)}/recover-permission`,
38
+ canonicalMismatches: (siteId) => `/sites/${encodeURIComponent(siteId)}/canonical-mismatches`,
39
+ topAssociation: (siteId) => `/sites/${encodeURIComponent(siteId)}/data/top-association`,
40
+ keywordSparklines: (siteId) => `/sites/${encodeURIComponent(siteId)}/data/keyword-sparklines`,
41
+ queryTrend: (siteId) => `/sites/${encodeURIComponent(siteId)}/data/query-trend`,
42
+ contentVelocity: (siteId) => `/sites/${encodeURIComponent(siteId)}/content-velocity`,
43
+ ctrCurve: (siteId) => `/sites/${encodeURIComponent(siteId)}/ctr-curve`,
44
+ darkTraffic: (siteId) => `/sites/${encodeURIComponent(siteId)}/dark-traffic`,
45
+ deviceGap: (siteId) => `/sites/${encodeURIComponent(siteId)}/device-gap`,
46
+ indexPercent: (siteId) => `/sites/${encodeURIComponent(siteId)}/index-percent`,
47
+ keywordBreadth: (siteId) => `/sites/${encodeURIComponent(siteId)}/keyword-breadth`,
48
+ positionDistribution: (siteId) => `/sites/${encodeURIComponent(siteId)}/position-distribution`
49
+ },
50
+ settings: { user: "/user/settings" },
51
+ teams: {
52
+ create: "/partner/teams",
53
+ byId: (teamId) => `/partner/teams/${encodeURIComponent(teamId)}`,
54
+ members: (teamId) => `/partner/teams/${encodeURIComponent(teamId)}/members`,
55
+ member: (teamId, userId) => `/partner/teams/${encodeURIComponent(teamId)}/members/${encodeURIComponent(userId)}`
56
+ },
57
+ realtime: {
58
+ partner: "/ws/partner",
59
+ user: "/ws/user"
60
+ }
61
+ };
62
+ const analyticsRoutes = {
63
+ whoami: "/api/__gsc/whoami",
64
+ sites: "/api/__gsc/sites",
65
+ site: {
66
+ sourceInfo: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/source-info`,
67
+ analysisSources: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/analysis-sources`,
68
+ analyze: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/analyze`,
69
+ rows: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/rows`,
70
+ rollup: (siteId, rollupId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/rollup/${encodeURIComponent(rollupId)}`,
71
+ backfill: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/backfill`,
72
+ sitemaps: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/sitemaps`,
73
+ sitemapHistory: (siteId, hash) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/sitemaps/${encodeURIComponent(hash)}`,
74
+ sitemapChanges: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/sitemaps/changes`,
75
+ inspections: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/inspections`,
76
+ inspectionHistory: (siteId, hash) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/inspections/${encodeURIComponent(hash)}`,
77
+ indexingUrls: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/indexing/urls`,
78
+ indexingDiagnostics: (siteId) => `/api/__gsc/sites/${encodeURIComponent(siteId)}/indexing/diagnostics`
79
+ }
80
+ };
81
+ const WEBHOOK_CONTRACT_VERSION = "2026-05-11";
82
+ const WEBHOOK_SIGNATURE_HEADER = "X-GSCDump-Signature";
83
+ const WEBHOOK_EVENT_HEADER = "X-GSCDump-Event";
84
+ const WEBHOOK_DELIVERY_HEADER = "X-GSCDump-Delivery";
85
+ const WEBHOOK_CONTRACT_VERSION_HEADER = "X-GSCDump-Contract-Version";
86
+ const WEBHOOK_TIMESTAMP_HEADER = "X-GSCDump-Timestamp";
87
+ const CANONICAL_WEBHOOK_EVENTS = [
88
+ "user.lifecycle.changed",
89
+ "site.lifecycle.changed",
90
+ "site.analytics.ready",
91
+ "site.indexing.ready",
92
+ "site.auth.failed",
93
+ "job.failed"
94
+ ];
95
+ const LEGACY_WEBHOOK_EVENTS = [
96
+ "job.completed",
97
+ "job.failed",
98
+ "site.completed",
99
+ "indexing.completed",
100
+ "auth.failed"
101
+ ];
102
+ const VALID_WEBHOOK_EVENTS = [...LEGACY_WEBHOOK_EVENTS, ...CANONICAL_WEBHOOK_EVENTS.filter((event) => !LEGACY_WEBHOOK_EVENTS.includes(event))];
103
+ const WEBHOOK_EVENT_ALIASES = {
104
+ "job.completed": "site.lifecycle.changed",
105
+ "job.failed": "job.failed",
106
+ "site.completed": "site.analytics.ready",
107
+ "indexing.completed": "site.indexing.ready",
108
+ "auth.failed": "site.auth.failed"
109
+ };
110
+ const GSCDUMP_ONBOARDING_CONTRACT_VERSION = "2026-05-11";
111
+ const GSCDUMP_REQUIRED_ANALYTICS_SCOPE = "https://www.googleapis.com/auth/webmasters.readonly";
112
+ const GSCDUMP_OPTIONAL_INDEXING_SCOPE = "https://www.googleapis.com/auth/indexing";
113
+ const accountStatuses = [
114
+ "disconnected",
115
+ "oauth_received",
116
+ "scope_missing",
117
+ "refresh_missing",
118
+ "db_provisioning",
119
+ "ready",
120
+ "reauth_required"
121
+ ];
122
+ const accountNextActions = [
123
+ "connect_google",
124
+ "reconnect_google",
125
+ "wait_for_provisioning",
126
+ "none"
127
+ ];
128
+ const propertyStatuses = [
129
+ "no_local_site",
130
+ "no_gsc_property",
131
+ "unverified_property",
132
+ "verified_candidate",
133
+ "registered",
134
+ "linked"
135
+ ];
136
+ const propertyNextActions = [
137
+ "create_site",
138
+ "verify_gsc_property",
139
+ "choose_property",
140
+ "register_site",
141
+ "none"
142
+ ];
143
+ const analyticsStatuses = [
144
+ "not_registered",
145
+ "queued",
146
+ "preparing",
147
+ "syncing",
148
+ "queryable_live",
149
+ "queryable_partial",
150
+ "ready",
151
+ "failed"
152
+ ];
153
+ const analyticsNextActions = [
154
+ "wait_for_sync",
155
+ "retry_sync",
156
+ "none"
157
+ ];
158
+ const querySourceModes = [
159
+ "none",
160
+ "live",
161
+ "d1",
162
+ "r2",
163
+ "mixed"
164
+ ];
165
+ const sitemapStatuses = [
166
+ "unknown",
167
+ "discovering",
168
+ "none_found",
169
+ "auto_submitted",
170
+ "syncing",
171
+ "ready",
172
+ "failed"
173
+ ];
174
+ const sitemapNextActions = [
175
+ "submit_sitemap",
176
+ "wait_for_sitemaps",
177
+ "retry_sitemaps",
178
+ "none"
179
+ ];
180
+ const indexingStatuses = [
181
+ "not_requested",
182
+ "missing_scope",
183
+ "insufficient_permission",
184
+ "waiting_for_sitemaps",
185
+ "discovering",
186
+ "checking",
187
+ "ready",
188
+ "budget_exhausted",
189
+ "no_urls",
190
+ "failed"
191
+ ];
192
+ const indexingNextActions = [
193
+ "reconnect_google",
194
+ "fix_gsc_permission",
195
+ "wait_for_sitemaps",
196
+ "wait_for_indexing",
197
+ "retry_indexing",
198
+ "none"
199
+ ];
200
+ const lifecycleWebhookEvents = [
201
+ "user.lifecycle.changed",
202
+ "site.lifecycle.changed",
203
+ "site.analytics.ready",
204
+ "site.indexing.ready",
205
+ "site.auth.failed",
206
+ "job.failed"
207
+ ];
208
+ const lifecycleErrorCodes = [
209
+ "missing_refresh_token",
210
+ "missing_analytics_scope",
211
+ "missing_indexing_scope",
212
+ "token_refresh_failed",
213
+ "permission_lost",
214
+ "insufficient_gsc_permission",
215
+ "gsc_property_not_found",
216
+ "gsc_property_unverified",
217
+ "user_database_not_provisioned",
218
+ "sync_failed",
219
+ "sitemap_sync_failed",
220
+ "indexing_failed"
221
+ ];
222
+ function parseGrantedScopes(scopes) {
223
+ return (scopes ?? "").split(/\s+/).map((s) => s.trim()).filter(Boolean);
224
+ }
225
+ function hasRequiredAnalyticsScope(scopes) {
226
+ return (Array.isArray(scopes) ? scopes : parseGrantedScopes(scopes)).includes(GSCDUMP_REQUIRED_ANALYTICS_SCOPE);
227
+ }
228
+ function hasOptionalIndexingScope(scopes) {
229
+ return (Array.isArray(scopes) ? scopes : parseGrantedScopes(scopes)).includes(GSCDUMP_OPTIONAL_INDEXING_SCOPE);
230
+ }
231
+ const unknownRecord = z.record(z.string(), z.unknown());
232
+ const builderStateSchema = unknownRecord;
233
+ const gscComparisonFilterSchema = z.enum([
234
+ "new",
235
+ "lost",
236
+ "improving",
237
+ "declining"
238
+ ]);
239
+ const gscApiRangeSchema = z.object({
240
+ start: z.string(),
241
+ end: z.string()
242
+ });
243
+ const countryRowSchema = z.object({
244
+ country: z.string(),
245
+ clicks: z.number(),
246
+ impressions: z.number(),
247
+ sum_position: z.number()
248
+ }).loose();
249
+ const countriesResponseSchema = z.object({
250
+ rows: z.array(countryRowSchema),
251
+ range: gscApiRangeSchema,
252
+ generatedAt: z.string(),
253
+ source: z.enum(["gsc-api", "engine"])
254
+ }).loose();
255
+ const searchAppearanceRowSchema = z.object({
256
+ searchAppearance: z.string(),
257
+ clicks: z.number(),
258
+ impressions: z.number(),
259
+ sum_position: z.number()
260
+ }).loose();
261
+ const searchAppearanceResponseSchema = z.object({
262
+ rows: z.array(searchAppearanceRowSchema),
263
+ range: gscApiRangeSchema,
264
+ generatedAt: z.string(),
265
+ source: z.enum(["gsc-api", "engine"])
266
+ }).loose();
267
+ const siteListItemSchema = z.object({
268
+ id: z.string(),
269
+ label: z.string(),
270
+ hostname: z.string(),
271
+ propertyType: z.enum(["domain", "url-prefix"]),
272
+ readBackend: z.enum(["d1", "r2"]).optional()
273
+ }).loose();
274
+ const sitemapHistoryRecordSchema = z.object({
275
+ path: z.string(),
276
+ capturedAt: z.string()
277
+ }).loose();
278
+ const sitemapHistoryResponseSchema = z.object({
279
+ path: z.string().nullable(),
280
+ snapshots: z.array(sitemapHistoryRecordSchema)
281
+ }).loose();
282
+ const inspectionHistoryRecordSchema = z.object({
283
+ url: z.string(),
284
+ inspectedAt: z.string()
285
+ }).loose();
286
+ const inspectionHistoryResponseSchema = z.object({
287
+ url: z.string().nullable(),
288
+ records: z.array(inspectionHistoryRecordSchema)
289
+ }).loose();
290
+ const sitemapIndexSchema = z.object({
291
+ version: z.literal(1),
292
+ records: z.record(z.string(), sitemapHistoryRecordSchema)
293
+ }).loose();
294
+ const inspectionIndexSchema = z.object({
295
+ version: z.literal(1),
296
+ records: z.record(z.string(), inspectionHistoryRecordSchema)
297
+ }).loose();
298
+ const rollupEnvelopeSchema = z.object({
299
+ version: z.literal(1),
300
+ id: z.string(),
301
+ builtAt: z.number(),
302
+ windowDays: z.number().nullable(),
303
+ payload: z.unknown()
304
+ }).loose();
305
+ const gscRowQueryMetaSchema = z.object({
306
+ sourceName: z.string(),
307
+ sourceKind: z.enum(["row", "sql"]),
308
+ queryMs: z.number()
309
+ }).loose();
310
+ const gscRowQueryResponseSchema = z.object({
311
+ rows: z.array(unknownRecord),
312
+ meta: gscRowQueryMetaSchema
313
+ }).loose();
314
+ const indexingUrlStatusSchema = z.enum([
315
+ "indexed",
316
+ "not_indexed",
317
+ "pending"
318
+ ]);
319
+ const indexingUrlRowSchema = z.object({
320
+ url: z.string(),
321
+ verdict: z.string().nullable(),
322
+ coverageState: z.string().nullable(),
323
+ indexingState: z.string().nullable(),
324
+ robotsTxtState: z.string().nullable(),
325
+ pageFetchState: z.string().nullable(),
326
+ lastCrawlTime: z.string().nullable(),
327
+ crawlingUserAgent: z.string().nullable(),
328
+ userCanonical: z.string().nullable(),
329
+ googleCanonical: z.string().nullable(),
330
+ sitemaps: z.array(z.string()).nullable(),
331
+ referringUrls: z.array(z.string()).nullable(),
332
+ mobileVerdict: z.string().nullable(),
333
+ mobileIssues: z.array(z.unknown()).nullable(),
334
+ richResultsVerdict: z.string().nullable(),
335
+ richResultsItems: z.array(z.unknown()).nullable(),
336
+ inspectionResultLink: z.string().nullable(),
337
+ firstCheckedAt: z.string(),
338
+ lastCheckedAt: z.string(),
339
+ checkCount: z.number()
340
+ }).loose();
341
+ const indexingUrlsResponseSchema = z.object({
342
+ urls: z.array(indexingUrlRowSchema),
343
+ pagination: z.object({
344
+ total: z.number(),
345
+ limit: z.number(),
346
+ offset: z.number(),
347
+ hasMore: z.boolean()
348
+ }).loose(),
349
+ meta: z.object({
350
+ siteUrl: z.string(),
351
+ status: z.string(),
352
+ issue: z.string().nullable()
353
+ }).loose()
354
+ }).loose();
355
+ const indexingIssueSchema = z.object({
356
+ type: z.string(),
357
+ label: z.string(),
358
+ severity: z.enum([
359
+ "error",
360
+ "warning",
361
+ "info"
362
+ ]),
363
+ count: z.number()
364
+ }).loose();
365
+ const indexingDiagnosticsSchema = z.object({
366
+ summary: z.object({
367
+ totalUrls: z.number(),
368
+ indexed: z.number(),
369
+ indexedPercent: z.number()
370
+ }).loose(),
371
+ issues: z.array(indexingIssueSchema),
372
+ meta: z.object({ siteUrl: z.string() }).loose()
373
+ }).loose();
374
+ const sitemapChangesResponseSchema = z.object({
375
+ added: z.array(z.object({
376
+ url: z.string(),
377
+ sitemap: z.string(),
378
+ firstSeenAt: z.number()
379
+ }).loose()),
380
+ removed: z.array(z.object({
381
+ url: z.string(),
382
+ sitemap: z.string(),
383
+ removedAt: z.number()
384
+ }).loose()),
385
+ summary: z.object({
386
+ totalAdded: z.number(),
387
+ totalRemoved: z.number(),
388
+ period: z.object({ days: z.number() })
389
+ }).loose()
390
+ }).loose();
391
+ const sourceInfoResponseSchema = z.object({
392
+ name: z.string(),
393
+ kind: z.enum(["row", "sql"]),
394
+ capabilities: z.object({ attachedTables: z.boolean().optional() }).loose(),
395
+ supportedAnalyzerIds: z.array(z.string()),
396
+ browserAttachEligible: z.boolean(),
397
+ identityAttrs: unknownRecord.nullable().optional()
398
+ }).loose();
399
+ const whoamiResponseSchema = z.object({
400
+ userId: z.string().nullable().optional(),
401
+ plan: z.string().nullable().optional(),
402
+ attrs: unknownRecord.optional()
403
+ }).loose();
404
+ const backfillRangeSchema = z.object({
405
+ startDate: z.string(),
406
+ endDate: z.string()
407
+ }).loose();
408
+ const backfillResponseSchema = z.object({
409
+ ok: z.boolean().optional(),
410
+ queued: z.boolean().optional()
411
+ }).loose();
412
+ const gscdumpTotalsSchema = z.object({
413
+ clicks: z.number(),
414
+ impressions: z.number(),
415
+ ctr: z.number(),
416
+ position: z.number()
417
+ });
418
+ const gscdumpMetaSchema = z.object({
419
+ siteUrl: z.string(),
420
+ syncStatus: z.string(),
421
+ newestDateSynced: z.string().nullable(),
422
+ oldestDateSynced: z.string().nullable(),
423
+ dataDelay: z.string(),
424
+ dataEndDate: z.string().nullable().optional(),
425
+ warnings: z.array(z.string()).optional(),
426
+ enrichment: z.object({
427
+ lastEnriched: z.number(),
428
+ isDue: z.boolean()
429
+ }).optional(),
430
+ backfill: z.object({
431
+ percent: z.number(),
432
+ daysRemaining: z.number().optional()
433
+ }).optional()
434
+ }).loose();
435
+ const gscdumpDataRowSchema = z.object({
436
+ clicks: z.number(),
437
+ impressions: z.number(),
438
+ ctr: z.number(),
439
+ position: z.number()
440
+ }).loose();
441
+ const gscdumpDataResponseSchema = z.object({
442
+ rows: z.array(gscdumpDataRowSchema),
443
+ totalCount: z.number(),
444
+ totals: gscdumpTotalsSchema,
445
+ meta: gscdumpMetaSchema
446
+ });
447
+ const gscdumpDataDetailResponseSchema = z.object({
448
+ daily: z.array(z.object({
449
+ date: z.string(),
450
+ clicks: z.number(),
451
+ impressions: z.number(),
452
+ ctr: z.number(),
453
+ position: z.number()
454
+ }).loose()),
455
+ totals: gscdumpTotalsSchema,
456
+ previousTotals: gscdumpTotalsSchema.optional(),
457
+ meta: gscdumpMetaSchema
458
+ });
459
+ const registerPartnerUserSchema = z.object({
460
+ userGoogleId: z.string().min(1),
461
+ userEmail: z.email(),
462
+ userName: z.string().optional(),
463
+ accessToken: z.string().min(1),
464
+ refreshToken: z.string().min(1),
465
+ tokenExpiresAt: z.number().optional()
466
+ });
467
+ const updatePartnerUserTokensSchema = z.object({
468
+ accessToken: z.string().min(1),
469
+ refreshToken: z.string().min(1),
470
+ tokenExpiresAt: z.number().optional()
471
+ });
472
+ const gscdumpUserRegistrationSchema = z.object({
473
+ userId: z.string(),
474
+ apiKey: z.string().optional(),
475
+ isNew: z.boolean().optional(),
476
+ status: z.enum(["provisioning", "ready"]).optional()
477
+ }).loose();
478
+ const gscdumpUserStatusSchema = z.object({
479
+ userId: z.string(),
480
+ status: z.enum([
481
+ "provisioning",
482
+ "ready",
483
+ "reauth_required"
484
+ ]),
485
+ databaseReady: z.boolean().optional(),
486
+ needsReauth: z.boolean().optional(),
487
+ reauthRequired: z.boolean().optional(),
488
+ reauthReason: z.string().nullable().optional(),
489
+ authFailureCount: z.number().optional(),
490
+ nextAction: z.enum(["reconnect_google", "none"]).optional(),
491
+ grantedScopes: z.string().nullable().optional()
492
+ }).loose();
493
+ const lifecycleProgressSchema = z.object({
494
+ completed: z.number(),
495
+ failed: z.number(),
496
+ total: z.number(),
497
+ percent: z.number()
498
+ });
499
+ const lifecycleErrorSchema = z.object({
500
+ code: z.enum(lifecycleErrorCodes),
501
+ message: z.string(),
502
+ retryable: z.boolean()
503
+ });
504
+ const partnerLifecycleAccountSchema = z.object({
505
+ status: z.enum(accountStatuses),
506
+ grantedScopes: z.array(z.string()),
507
+ missingScopes: z.array(z.string()),
508
+ nextAction: z.enum(accountNextActions)
509
+ }).loose();
510
+ const partnerLifecycleSiteSchema = z.object({
511
+ siteId: z.string(),
512
+ externalSiteId: z.string().nullable(),
513
+ requestedUrl: z.string(),
514
+ gscPropertyUrl: z.string().nullable(),
515
+ permissionLevel: z.string().nullable(),
516
+ property: z.object({
517
+ status: z.enum(propertyStatuses),
518
+ nextAction: z.enum(propertyNextActions)
519
+ }).loose(),
520
+ analytics: z.object({
521
+ status: z.enum(analyticsStatuses),
522
+ progress: lifecycleProgressSchema,
523
+ queryable: z.boolean(),
524
+ sourceMode: z.enum(querySourceModes),
525
+ syncedRange: z.object({
526
+ oldest: z.string().nullable(),
527
+ newest: z.string().nullable()
528
+ }).loose(),
529
+ nextAction: z.enum(analyticsNextActions)
530
+ }).loose(),
531
+ sitemaps: z.object({
532
+ status: z.enum(sitemapStatuses),
533
+ discoveredCount: z.number(),
534
+ nextAction: z.enum(sitemapNextActions)
535
+ }).loose(),
536
+ indexing: z.object({
537
+ status: z.enum(indexingStatuses),
538
+ eligible: z.boolean(),
539
+ reason: z.string().nullable(),
540
+ progress: lifecycleProgressSchema,
541
+ nextAction: z.enum(indexingNextActions)
542
+ }).loose(),
543
+ latestError: lifecycleErrorSchema.nullable(),
544
+ lifecycleRevision: z.number(),
545
+ updatedAt: z.string()
546
+ }).loose();
547
+ const partnerLifecycleResponseSchema = z.object({
548
+ contractVersion: z.literal(GSCDUMP_ONBOARDING_CONTRACT_VERSION),
549
+ userId: z.string(),
550
+ partnerId: z.string().nullable(),
551
+ account: partnerLifecycleAccountSchema,
552
+ sites: z.array(partnerLifecycleSiteSchema)
553
+ }).loose();
554
+ const gscdumpAvailableSiteSchema = z.object({
555
+ siteUrl: z.string(),
556
+ permissionLevel: z.string(),
557
+ registered: z.boolean(),
558
+ siteId: z.string().optional(),
559
+ syncStatus: z.enum([
560
+ "pending",
561
+ "syncing",
562
+ "synced",
563
+ "error"
564
+ ]).nullable().optional(),
565
+ syncProgress: z.object({
566
+ completed: z.number(),
567
+ failed: z.number().optional(),
568
+ total: z.number(),
569
+ percent: z.number()
570
+ }).optional(),
571
+ lastSyncAt: z.number().nullable().optional(),
572
+ newestDateSynced: z.string().nullable().optional(),
573
+ oldestDateSynced: z.string().nullable().optional()
574
+ }).loose();
575
+ const gscdumpUserSiteSchema = z.object({
576
+ siteId: z.string(),
577
+ siteUrl: z.string(),
578
+ syncStatus: z.enum([
579
+ "idle",
580
+ "pending",
581
+ "syncing",
582
+ "synced",
583
+ "error"
584
+ ]),
585
+ lastSyncAt: z.number().nullable(),
586
+ newestDateSynced: z.string().nullable(),
587
+ oldestDateSynced: z.string().nullable()
588
+ }).loose();
589
+ const gscdumpSiteRegistrationSchema = z.object({
590
+ siteId: z.string(),
591
+ status: z.enum([
592
+ "idle",
593
+ "pending",
594
+ "syncing",
595
+ "synced",
596
+ "error"
597
+ ]),
598
+ message: z.string().optional(),
599
+ existing: z.boolean().optional(),
600
+ indexingEligible: z.boolean().optional(),
601
+ indexingIneligibleReason: z.enum(["missing_indexing_scope", "insufficient_gsc_permission"]).optional(),
602
+ indexingPermissionLevel: z.string().nullable().optional(),
603
+ grantedScopes: z.array(z.string()).optional()
604
+ }).loose();
605
+ const registerPartnerSiteSchema = z.object({
606
+ userId: z.string(),
607
+ siteUrl: z.string().min(1),
608
+ requestedUrl: z.string().optional(),
609
+ gscPropertyUrl: z.string().optional(),
610
+ externalSiteId: z.string().optional(),
611
+ externalSiteUrl: z.string().optional(),
612
+ webhookUrl: z.url().optional(),
613
+ webhookEvents: z.array(z.enum(VALID_WEBHOOK_EVENTS)).optional(),
614
+ teamId: z.string().optional()
615
+ });
616
+ const bulkRegisterPartnerSitesSchema = z.object({
617
+ userId: z.string().optional(),
618
+ siteUrls: z.array(z.string().min(1)).optional(),
619
+ sites: z.array(z.object({
620
+ siteUrl: z.string().optional(),
621
+ requestedUrl: z.string().optional(),
622
+ gscPropertyUrl: z.string().optional(),
623
+ externalSiteId: z.string().optional(),
624
+ externalSiteUrl: z.string().optional(),
625
+ webhookUrl: z.url().optional(),
626
+ webhookEvents: z.array(z.enum(VALID_WEBHOOK_EVENTS)).optional()
627
+ }).loose()).optional()
628
+ }).refine((value) => (value.siteUrls?.length ?? 0) > 0 || (value.sites?.length ?? 0) > 0, { message: "siteUrls or sites is required" });
629
+ const bulkRegisterPartnerSitesResponseSchema = z.object({
630
+ results: z.array(z.object({
631
+ siteUrl: z.string(),
632
+ siteId: z.string().optional(),
633
+ status: z.enum([
634
+ "registered",
635
+ "already_exists",
636
+ "not_found",
637
+ "error"
638
+ ]),
639
+ error: z.string().optional(),
640
+ site: unknownRecord.nullable().optional(),
641
+ indexingEligible: z.boolean().optional(),
642
+ indexingIneligibleReason: z.enum(["missing_indexing_scope", "insufficient_gsc_permission"]).optional(),
643
+ indexingPermissionLevel: z.string().nullable().optional(),
644
+ grantedScopes: z.array(z.string()).optional()
645
+ }).loose()),
646
+ summary: z.object({
647
+ registered: z.number(),
648
+ alreadyExists: z.number(),
649
+ notFound: z.number(),
650
+ errors: z.number()
651
+ })
652
+ }).loose();
653
+ const dataQueryOptionsSchema = z.object({
654
+ comparison: builderStateSchema.optional(),
655
+ filter: gscComparisonFilterSchema.optional()
656
+ }).optional();
657
+ const dataDetailOptionsSchema = z.object({ comparison: builderStateSchema.optional() }).optional();
658
+ const gscdumpAnalysisPresetSchema = z.enum([
659
+ "striking-distance",
660
+ "opportunity",
661
+ "decay",
662
+ "zero-click",
663
+ "non-brand",
664
+ "brand-only",
665
+ "movers-rising",
666
+ "movers-declining"
667
+ ]);
668
+ const gscdumpAnalysisParamsSchema = z.object({
669
+ preset: gscdumpAnalysisPresetSchema,
670
+ startDate: z.string(),
671
+ endDate: z.string(),
672
+ prevStartDate: z.string().optional(),
673
+ prevEndDate: z.string().optional(),
674
+ brandTerms: z.string().optional(),
675
+ limit: z.number().optional(),
676
+ offset: z.number().optional(),
677
+ search: z.string().optional(),
678
+ minImpressions: z.number().optional(),
679
+ minPosition: z.number().optional(),
680
+ maxPosition: z.number().optional(),
681
+ maxCtr: z.number().optional()
682
+ }).superRefine((value, ctx) => {
683
+ if ((value.preset === "brand-only" || value.preset === "non-brand") && !value.brandTerms?.trim()) ctx.addIssue({
684
+ code: "custom",
685
+ path: ["brandTerms"],
686
+ message: "brandTerms is required for brand/non-brand presets"
687
+ });
688
+ });
689
+ const gscdumpAnalysisResponseSchema = z.object({
690
+ preset: gscdumpAnalysisPresetSchema,
691
+ keywords: z.array(unknownRecord),
692
+ totalCount: z.number(),
693
+ summary: unknownRecord.optional(),
694
+ meta: gscdumpMetaSchema
695
+ }).loose();
696
+ const gscdumpSitemapsResponseSchema = z.object({
697
+ sitemaps: z.array(unknownRecord),
698
+ history: z.array(unknownRecord),
699
+ perSitemapHistory: z.record(z.string(), z.array(unknownRecord)),
700
+ meta: z.object({
701
+ siteUrl: z.string(),
702
+ syncStatus: z.string().nullable()
703
+ }).loose()
704
+ }).loose();
705
+ const gscdumpSitemapChangesResponseSchema = z.object({
706
+ added: z.array(unknownRecord),
707
+ removed: z.array(unknownRecord),
708
+ summary: z.object({
709
+ totalAdded: z.number(),
710
+ totalRemoved: z.number(),
711
+ period: z.object({ days: z.number() })
712
+ }).optional()
713
+ }).loose();
714
+ const indexingUrlsParamsSchema = z.object({
715
+ limit: z.number().optional(),
716
+ offset: z.number().optional(),
717
+ status: z.enum([
718
+ "indexed",
719
+ "not_indexed",
720
+ "pending"
721
+ ]).optional(),
722
+ issue: z.string().optional(),
723
+ search: z.string().optional()
724
+ }).optional();
725
+ const gscdumpIndexingResponseSchema = z.object({
726
+ trend: z.array(z.object({
727
+ date: z.string(),
728
+ totalUrls: z.number(),
729
+ indexedCount: z.number().nullable(),
730
+ notIndexedCount: z.number().nullable(),
731
+ errorCount: z.number().nullable(),
732
+ indexedPercent: z.number(),
733
+ issues: z.object({
734
+ blockedByRobots: z.number().nullable(),
735
+ noindexDetected: z.number().nullable(),
736
+ soft404: z.number().nullable(),
737
+ redirect: z.number().nullable(),
738
+ notFound: z.number().nullable(),
739
+ serverError: z.number().nullable()
740
+ }).loose(),
741
+ coverage: z.object({
742
+ submittedIndexed: z.number().nullable(),
743
+ crawledNotIndexed: z.number().nullable(),
744
+ discoveredNotCrawled: z.number().nullable()
745
+ }).loose(),
746
+ signals: z.object({
747
+ mobilePass: z.number(),
748
+ mobileFail: z.number(),
749
+ richResultsPass: z.number(),
750
+ richResultsFail: z.number()
751
+ }).loose()
752
+ }).loose()),
753
+ summary: z.object({
754
+ totalUrls: z.number(),
755
+ indexed: z.number(),
756
+ notIndexed: z.number(),
757
+ pending: z.number(),
758
+ indexedPercent: z.number(),
759
+ oldestCheck: z.string().nullable(),
760
+ newestCheck: z.string().nullable(),
761
+ change7d: z.number().nullable(),
762
+ change28d: z.number().nullable(),
763
+ signals: z.object({
764
+ mobilePass: z.number(),
765
+ mobileFail: z.number(),
766
+ mobileUnspecified: z.number(),
767
+ richResultsPass: z.number(),
768
+ richResultsFail: z.number(),
769
+ richResultTypes: z.array(z.object({
770
+ type: z.string(),
771
+ count: z.number()
772
+ }).loose()),
773
+ crawlingMobile: z.number(),
774
+ crawlingDesktop: z.number()
775
+ }).loose()
776
+ }).loose(),
777
+ meta: z.object({
778
+ siteUrl: z.string(),
779
+ syncStatus: z.string().nullable(),
780
+ indexingStatus: z.enum([
781
+ "pending",
782
+ "partial",
783
+ "complete"
784
+ ]),
785
+ indexingProgress: z.number(),
786
+ sitemapTotal: z.number(),
787
+ inspectedCount: z.number(),
788
+ noSitemapsSubmitted: z.boolean(),
789
+ sitemapsPending: z.boolean(),
790
+ rollupBuiltAt: z.number().optional()
791
+ }).loose()
792
+ }).loose();
793
+ const gscdumpIndexingUrlsResponseSchema = z.object({
794
+ urls: z.array(unknownRecord),
795
+ pagination: z.object({
796
+ total: z.number(),
797
+ limit: z.number(),
798
+ offset: z.number(),
799
+ hasMore: z.boolean()
800
+ }),
801
+ meta: z.object({
802
+ siteUrl: z.string(),
803
+ status: z.string(),
804
+ issue: z.string().nullable()
805
+ }).loose()
806
+ }).loose();
807
+ const gscdumpIndexingDiagnosticsResponseSchema = z.object({
808
+ summary: z.object({
809
+ totalUrls: z.number(),
810
+ indexed: z.number(),
811
+ indexedPercent: z.number()
812
+ }).loose(),
813
+ issues: z.array(unknownRecord),
814
+ meta: z.object({ siteUrl: z.string() }).loose()
815
+ }).loose();
816
+ const gscdumpUserSettingsSchema = z.object({ browserAnalyzerEnabled: z.boolean() }).loose();
817
+ const gscdumpPermissionRecoverySchema = z.object({
818
+ success: z.boolean(),
819
+ permissionLevel: z.string().nullable(),
820
+ jobsQueued: z.number(),
821
+ message: z.string()
822
+ }).loose();
823
+ const gscdumpUserMeResponseSchema = z.object({
824
+ id: z.string(),
825
+ name: z.string().optional(),
826
+ email: z.string(),
827
+ picture: z.string().optional(),
828
+ setupComplete: z.boolean(),
829
+ databaseReady: z.boolean(),
830
+ plan: z.string(),
831
+ accountStatus: z.enum(accountStatuses),
832
+ accountNextAction: z.enum(accountNextActions),
833
+ missingScopes: z.array(z.string()),
834
+ browserAnalyzerEnabled: z.boolean(),
835
+ stats: z.object({
836
+ activeSessions: z.number(),
837
+ totalApiCalls: z.number(),
838
+ lastUsed: z.number().nullable()
839
+ }).nullable()
840
+ }).loose();
841
+ const gscdumpHealthResponseSchema = z.object({
842
+ timestamp: z.number(),
843
+ jobs: z.object({
844
+ byStatus: z.record(z.string(), z.number()),
845
+ byQueue: z.record(z.string(), z.number()),
846
+ stuck: z.number(),
847
+ oldCompleted: z.number()
848
+ }).loose(),
849
+ failures: z.object({ lastHour: z.number() }).loose(),
850
+ users: z.object({ needsReauth: z.number() }).loose(),
851
+ throughput: z.object({ completedLastHour: z.number() }).loose(),
852
+ totals: z.object({
853
+ users: z.number(),
854
+ sites: z.number(),
855
+ byPlan: z.record(z.string(), z.number())
856
+ }).loose()
857
+ }).loose();
858
+ const syncProgressPhaseCountsSchema = z.object({
859
+ total: z.number(),
860
+ done: z.number(),
861
+ pending: z.number(),
862
+ stuck: z.number(),
863
+ failed: z.number(),
864
+ percent: z.number(),
865
+ rows: z.number()
866
+ }).loose();
867
+ const gscdumpSyncProgressResponseSchema = z.object({
868
+ summary: z.object({
869
+ total: z.number(),
870
+ inInitial: z.number(),
871
+ inBackfill: z.number(),
872
+ complete: z.number(),
873
+ stalled: z.number(),
874
+ authBlocked: z.number(),
875
+ totalRows: z.number(),
876
+ avgInitialPercent: z.number(),
877
+ avgBackfillPercent: z.number()
878
+ }).loose(),
879
+ sites: z.array(z.object({
880
+ id: z.string(),
881
+ userId: z.number(),
882
+ partnerId: z.number().nullable(),
883
+ siteUrl: z.string(),
884
+ syncStatus: z.string().nullable(),
885
+ lastError: z.string().nullable(),
886
+ createdAt: z.number(),
887
+ oldestDateSynced: z.string().nullable(),
888
+ newestDateSynced: z.string().nullable(),
889
+ oldestDateAvailable: z.string().nullable(),
890
+ userEmail: z.string().nullable(),
891
+ partnerName: z.string().nullable(),
892
+ needsReauth: z.boolean(),
893
+ authFailureCount: z.number(),
894
+ currentPhase: z.enum([
895
+ "initial",
896
+ "backfill",
897
+ "complete"
898
+ ]),
899
+ isStalled: z.boolean(),
900
+ stallDays: z.number(),
901
+ needsContinuation: z.boolean(),
902
+ missingDays: z.number(),
903
+ initial: syncProgressPhaseCountsSchema,
904
+ backfill: syncProgressPhaseCountsSchema.extend({
905
+ processing: z.number(),
906
+ daysTarget: z.number(),
907
+ daysQueued: z.number()
908
+ }).loose(),
909
+ tables: z.record(z.string(), z.object({
910
+ percent: z.number(),
911
+ rows: z.number()
912
+ }).loose()),
913
+ overallPercent: z.number(),
914
+ totalRows: z.number(),
915
+ dateStatuses: z.array(z.object({
916
+ date: z.string(),
917
+ status: z.enum([
918
+ "completed",
919
+ "queued",
920
+ "processing",
921
+ "failed"
922
+ ])
923
+ }).loose())
924
+ }).loose()),
925
+ pagination: z.object({
926
+ total: z.number(),
927
+ limit: z.number(),
928
+ offset: z.number(),
929
+ hasMore: z.boolean()
930
+ }).loose(),
931
+ hasD1Stats: z.boolean()
932
+ }).loose();
933
+ const syncJobsQueueCountsSchema = z.object({
934
+ queued: z.number(),
935
+ processing: z.number()
936
+ }).loose();
937
+ const gscdumpSyncJobsResponseSchema = z.object({
938
+ jobs: z.array(z.object({
939
+ id: z.number(),
940
+ userSiteId: z.string().nullable(),
941
+ tableName: z.string().optional(),
942
+ tableTier: z.string().optional(),
943
+ date: z.string().optional(),
944
+ priority: z.string().optional(),
945
+ status: z.enum([
946
+ "queued",
947
+ "processing",
948
+ "completed",
949
+ "failed",
950
+ "scheduled"
951
+ ]),
952
+ siteUrl: z.string().nullable(),
953
+ userEmail: z.string().nullable().optional(),
954
+ rowsFetched: z.number().nullable(),
955
+ rowsInserted: z.number().nullable(),
956
+ error: z.string().nullable(),
957
+ retryCount: z.number(),
958
+ queuedAt: z.number(),
959
+ startedAt: z.number().nullable(),
960
+ completedAt: z.number().nullable()
961
+ }).loose()),
962
+ summary: z.object({
963
+ queued: z.number(),
964
+ processing: z.number(),
965
+ completed: z.number(),
966
+ failed: z.number()
967
+ }).loose(),
968
+ queues: z.record(z.string(), syncJobsQueueCountsSchema),
969
+ tiers: z.object({
970
+ critical: syncJobsQueueCountsSchema.optional(),
971
+ standard: syncJobsQueueCountsSchema.optional(),
972
+ extended: syncJobsQueueCountsSchema.optional()
973
+ }).loose().optional()
974
+ }).loose();
975
+ const gscdumpSiteReportResponseSchema = z.object({
976
+ status: z.enum(["done", "error"]),
977
+ cached: z.boolean(),
978
+ result: z.unknown().optional(),
979
+ error: z.string().optional()
980
+ }).loose();
981
+ const gscdumpTopAssociationParamsSchema = z.object({
982
+ type: z.enum(["topPage", "topKeyword"]),
983
+ identifier: z.string().min(1),
984
+ startDate: z.string(),
985
+ endDate: z.string()
986
+ });
987
+ const gscdumpTopAssociationResponseSchema = z.object({ value: z.string().nullable() }).loose();
988
+ const gscdumpAnalysisSourcesResponseSchema = z.object({
989
+ tables: z.record(z.string(), z.array(z.string())),
990
+ generatedAt: z.string(),
991
+ manifestVersion: z.string()
992
+ }).loose();
993
+ const gscdumpKeywordSparklinesParamsSchema = z.object({
994
+ keywords: z.array(z.string()).min(1).max(20),
995
+ startDate: z.string(),
996
+ endDate: z.string()
997
+ });
998
+ const gscdumpKeywordSparklinesResponseSchema = z.object({ sparklines: z.record(z.string(), z.array(z.number())) }).loose();
999
+ const gscdumpQueryTrendParamsSchema = z.object({
1000
+ startDate: z.string(),
1001
+ endDate: z.string(),
1002
+ prevStartDate: z.string().optional(),
1003
+ prevEndDate: z.string().optional()
1004
+ });
1005
+ const gscdumpQueryTrendResponseSchema = z.object({
1006
+ daily: z.array(z.object({
1007
+ date: z.string(),
1008
+ queryCount: z.number()
1009
+ }).loose()),
1010
+ total: z.number(),
1011
+ previousTotal: z.number().optional(),
1012
+ meta: z.object({
1013
+ siteUrl: z.string(),
1014
+ syncStatus: z.string().nullable()
1015
+ }).loose()
1016
+ }).loose();
1017
+ const gscdumpDateRangeParamsSchema = z.object({
1018
+ startDate: z.string(),
1019
+ endDate: z.string()
1020
+ });
1021
+ const gscdumpIndexPercentParamsSchema = z.object({
1022
+ invisibleLimit: z.number().optional(),
1023
+ invisibleOffset: z.number().optional(),
1024
+ orphanLimit: z.number().optional()
1025
+ }).optional();
1026
+ const gscdumpCanonicalMismatchesResponseSchema = z.object({
1027
+ mismatches: z.array(z.object({
1028
+ url: z.string(),
1029
+ userCanonical: z.string(),
1030
+ googleCanonical: z.string(),
1031
+ verdict: z.string().nullable(),
1032
+ coverageState: z.string().nullable(),
1033
+ lastCrawlTime: z.string().nullable(),
1034
+ lastCheckedAt: z.string().nullable()
1035
+ }).loose()),
1036
+ totalCount: z.number(),
1037
+ consolidationTargets: z.array(z.object({
1038
+ google_canonical: z.string(),
1039
+ count: z.number()
1040
+ }).loose()),
1041
+ trend: z.array(z.object({
1042
+ date: z.string(),
1043
+ count: z.number()
1044
+ }).loose()),
1045
+ meta: z.object({
1046
+ siteUrl: z.string(),
1047
+ syncStatus: z.string().nullable()
1048
+ }).loose()
1049
+ }).loose();
1050
+ const gscdumpIndexPercentResponseSchema = z.object({
1051
+ trend: z.array(z.object({
1052
+ date: z.string(),
1053
+ percent: z.number(),
1054
+ total: z.number(),
1055
+ visible: z.number(),
1056
+ added: z.number().nullable(),
1057
+ removed: z.number().nullable()
1058
+ }).loose()),
1059
+ invisibleUrls: z.array(z.object({
1060
+ url: z.string(),
1061
+ firstSeen: z.string().optional(),
1062
+ lastmod: z.string().nullable()
1063
+ }).loose()),
1064
+ invisibleCount: z.number(),
1065
+ orphanPages: z.array(z.object({
1066
+ url: z.string(),
1067
+ impressions: z.number().nullable(),
1068
+ clicks: z.number().nullable()
1069
+ }).loose()),
1070
+ orphanCount: z.number(),
1071
+ sitemaps: z.array(z.object({
1072
+ path: z.string(),
1073
+ urlCount: z.number(),
1074
+ isIndex: z.boolean()
1075
+ }).loose()),
1076
+ summary: z.object({
1077
+ currentPercent: z.number(),
1078
+ totalSitemapUrls: z.number(),
1079
+ visibleUrls: z.number(),
1080
+ change7d: z.number().nullable(),
1081
+ change28d: z.number().nullable(),
1082
+ dataDate: z.string()
1083
+ }).loose(),
1084
+ meta: z.object({
1085
+ siteUrl: z.string(),
1086
+ syncStatus: z.string().nullable(),
1087
+ newestDateSynced: z.string().nullable()
1088
+ }).loose()
1089
+ }).loose();
1090
+ const gscdumpDeletePartnerUserResponseSchema = z.object({
1091
+ ok: z.literal(true),
1092
+ queued: z.literal(true),
1093
+ userId: z.number(),
1094
+ publicId: z.string()
1095
+ }).loose();
1096
+ const gscdumpTeamRoleSchema = z.enum([
1097
+ "admin",
1098
+ "editor",
1099
+ "viewer"
1100
+ ]);
1101
+ const gscdumpTeamRowSchema = z.object({
1102
+ id: z.string(),
1103
+ ownerId: z.number(),
1104
+ name: z.string(),
1105
+ personalTeam: z.boolean(),
1106
+ createdAt: z.number(),
1107
+ updatedAt: z.number()
1108
+ }).loose();
1109
+ const gscdumpTeamMemberRowSchema = z.object({
1110
+ userId: z.number(),
1111
+ publicId: z.string(),
1112
+ name: z.string().nullable(),
1113
+ email: z.email(),
1114
+ picture: z.string().nullable(),
1115
+ role: gscdumpTeamRoleSchema,
1116
+ joinedAt: z.number()
1117
+ }).loose();
1118
+ const createPartnerTeamSchema = z.object({
1119
+ ownerUserId: z.string(),
1120
+ name: z.string().min(2).max(60),
1121
+ personalTeam: z.boolean().optional()
1122
+ });
1123
+ const addPartnerTeamMemberSchema = z.object({
1124
+ userId: z.string(),
1125
+ role: gscdumpTeamRoleSchema
1126
+ });
1127
+ const bindPartnerSiteTeamSchema = z.object({ teamId: z.string().nullable() });
1128
+ const partnerRealtimeEventSchema = z.discriminatedUnion("event", [
1129
+ z.object({
1130
+ event: z.literal("sync.progress"),
1131
+ siteId: z.string(),
1132
+ siteUrl: z.string(),
1133
+ table: z.string(),
1134
+ date: z.string(),
1135
+ progress: z.number()
1136
+ }).loose(),
1137
+ z.object({
1138
+ event: z.literal("sync.complete"),
1139
+ userId: z.number(),
1140
+ siteId: z.string(),
1141
+ siteUrl: z.string(),
1142
+ table: z.string(),
1143
+ date: z.string(),
1144
+ rowsFetched: z.number(),
1145
+ rowsInserted: z.number(),
1146
+ timestamp: z.number()
1147
+ }).loose(),
1148
+ z.object({
1149
+ event: z.literal("sync.job_complete"),
1150
+ userId: z.number(),
1151
+ siteId: z.string(),
1152
+ siteUrl: z.string(),
1153
+ table: z.string(),
1154
+ date: z.string(),
1155
+ rowsFetched: z.number(),
1156
+ rowsInserted: z.number(),
1157
+ syncStatus: z.string(),
1158
+ timestamp: z.number()
1159
+ }).loose(),
1160
+ z.object({
1161
+ event: z.literal("sync.site_complete"),
1162
+ userId: z.number(),
1163
+ siteId: z.string(),
1164
+ siteUrl: z.string(),
1165
+ syncStatus: z.string(),
1166
+ timestamp: z.number()
1167
+ }).loose(),
1168
+ z.object({
1169
+ event: z.literal("sync.failed"),
1170
+ userId: z.number(),
1171
+ siteId: z.string(),
1172
+ siteUrl: z.string(),
1173
+ table: z.string(),
1174
+ date: z.string(),
1175
+ error: z.string(),
1176
+ timestamp: z.number()
1177
+ }).loose(),
1178
+ z.object({
1179
+ event: z.literal("job.failed"),
1180
+ siteId: z.string(),
1181
+ siteUrl: z.string(),
1182
+ table: z.string(),
1183
+ date: z.string(),
1184
+ error: z.string(),
1185
+ timestamp: z.number()
1186
+ }).loose(),
1187
+ z.object({
1188
+ event: z.literal("site.added"),
1189
+ userId: z.number(),
1190
+ siteId: z.string(),
1191
+ siteUrl: z.string()
1192
+ }).loose(),
1193
+ z.object({
1194
+ event: z.literal("site.removed"),
1195
+ userId: z.number(),
1196
+ siteId: z.string(),
1197
+ siteUrl: z.string()
1198
+ }).loose(),
1199
+ z.object({
1200
+ event: z.literal("auth.failed"),
1201
+ userId: z.number(),
1202
+ siteId: z.string(),
1203
+ siteUrl: z.string(),
1204
+ error: z.string(),
1205
+ timestamp: z.number()
1206
+ }).loose(),
1207
+ z.object({
1208
+ event: z.literal("auth.needs_reauth"),
1209
+ userId: z.number(),
1210
+ failureCount: z.number(),
1211
+ timestamp: z.number()
1212
+ }).loose(),
1213
+ z.object({
1214
+ event: z.literal("enrichment.complete"),
1215
+ siteId: z.string(),
1216
+ userId: z.number(),
1217
+ timestamp: z.number()
1218
+ }).loose()
1219
+ ]);
1220
+ const canonicalWebhookEventTypeSchema = z.enum(CANONICAL_WEBHOOK_EVENTS);
1221
+ const legacyWebhookEventTypeSchema = z.enum(LEGACY_WEBHOOK_EVENTS);
1222
+ const webhookEventTypeSchema = z.enum(VALID_WEBHOOK_EVENTS);
1223
+ const jobCompletedWebhookPayloadSchema = z.object({
1224
+ event: z.literal("job.completed"),
1225
+ siteId: z.string(),
1226
+ siteUrl: z.string(),
1227
+ table: z.string().optional(),
1228
+ date: z.string(),
1229
+ rowsFetched: z.number(),
1230
+ rowsInserted: z.number(),
1231
+ timestamp: z.number()
1232
+ }).loose();
1233
+ const jobFailedWebhookPayloadSchema = z.object({
1234
+ event: z.literal("job.failed"),
1235
+ siteId: z.string(),
1236
+ siteUrl: z.string(),
1237
+ table: z.string(),
1238
+ date: z.string(),
1239
+ error: z.string(),
1240
+ timestamp: z.number()
1241
+ }).loose();
1242
+ const siteCompletedWebhookPayloadSchema = z.object({
1243
+ event: z.literal("site.completed"),
1244
+ siteId: z.string(),
1245
+ siteUrl: z.string(),
1246
+ status: z.string(),
1247
+ daysSynced: z.number(),
1248
+ failedJobs: z.number(),
1249
+ oldestDateSynced: z.string().nullable().optional(),
1250
+ newestDateSynced: z.string().nullable().optional(),
1251
+ timestamp: z.number()
1252
+ }).loose();
1253
+ const indexingCompletedWebhookPayloadSchema = z.object({
1254
+ event: z.literal("indexing.completed"),
1255
+ siteId: z.string(),
1256
+ siteUrl: z.string(),
1257
+ totalUrls: z.number(),
1258
+ indexedCount: z.number(),
1259
+ notIndexedCount: z.number(),
1260
+ errorCount: z.number(),
1261
+ urlsChecked: z.number(),
1262
+ timestamp: z.number()
1263
+ }).loose();
1264
+ const authFailedWebhookPayloadSchema = z.object({
1265
+ event: z.literal("auth.failed"),
1266
+ siteId: z.string(),
1267
+ siteUrl: z.string(),
1268
+ reason: z.string().optional(),
1269
+ message: z.string().optional(),
1270
+ reauthRequired: z.boolean().optional(),
1271
+ authFailureCount: z.number().optional(),
1272
+ error: z.string().optional(),
1273
+ timestamp: z.number().optional()
1274
+ }).loose();
1275
+ const legacyWebhookPayloadSchema = z.discriminatedUnion("event", [
1276
+ jobCompletedWebhookPayloadSchema,
1277
+ jobFailedWebhookPayloadSchema,
1278
+ siteCompletedWebhookPayloadSchema,
1279
+ indexingCompletedWebhookPayloadSchema,
1280
+ authFailedWebhookPayloadSchema
1281
+ ]);
1282
+ const partnerWebhookDataSchema = z.discriminatedUnion("legacyEvent", [
1283
+ z.object({
1284
+ legacyEvent: z.literal("job.completed"),
1285
+ legacyPayload: jobCompletedWebhookPayloadSchema,
1286
+ event: z.literal("job.completed").optional(),
1287
+ siteId: z.string(),
1288
+ siteUrl: z.string(),
1289
+ table: z.string().optional(),
1290
+ date: z.string(),
1291
+ rowsFetched: z.number(),
1292
+ rowsInserted: z.number(),
1293
+ timestamp: z.number()
1294
+ }).loose(),
1295
+ z.object({
1296
+ legacyEvent: z.literal("job.failed"),
1297
+ legacyPayload: jobFailedWebhookPayloadSchema,
1298
+ event: z.literal("job.failed").optional(),
1299
+ siteId: z.string(),
1300
+ siteUrl: z.string(),
1301
+ table: z.string(),
1302
+ date: z.string(),
1303
+ error: z.string(),
1304
+ timestamp: z.number()
1305
+ }).loose(),
1306
+ z.object({
1307
+ legacyEvent: z.literal("site.completed"),
1308
+ legacyPayload: siteCompletedWebhookPayloadSchema,
1309
+ event: z.literal("site.completed").optional(),
1310
+ siteId: z.string(),
1311
+ siteUrl: z.string(),
1312
+ status: z.string(),
1313
+ daysSynced: z.number(),
1314
+ failedJobs: z.number(),
1315
+ oldestDateSynced: z.string().nullable().optional(),
1316
+ newestDateSynced: z.string().nullable().optional(),
1317
+ timestamp: z.number()
1318
+ }).loose(),
1319
+ z.object({
1320
+ legacyEvent: z.literal("indexing.completed"),
1321
+ legacyPayload: indexingCompletedWebhookPayloadSchema,
1322
+ event: z.literal("indexing.completed").optional(),
1323
+ siteId: z.string(),
1324
+ siteUrl: z.string(),
1325
+ totalUrls: z.number(),
1326
+ indexedCount: z.number(),
1327
+ notIndexedCount: z.number(),
1328
+ errorCount: z.number(),
1329
+ urlsChecked: z.number(),
1330
+ timestamp: z.number()
1331
+ }).loose(),
1332
+ z.object({
1333
+ legacyEvent: z.literal("auth.failed"),
1334
+ legacyPayload: authFailedWebhookPayloadSchema,
1335
+ event: z.literal("auth.failed").optional(),
1336
+ siteId: z.string(),
1337
+ siteUrl: z.string(),
1338
+ reason: z.string().optional(),
1339
+ message: z.string().optional(),
1340
+ reauthRequired: z.boolean().optional(),
1341
+ authFailureCount: z.number().optional(),
1342
+ error: z.string().optional(),
1343
+ timestamp: z.number().optional()
1344
+ }).loose(),
1345
+ z.object({ legacyEvent: z.literal("user.lifecycle.changed") }).loose(),
1346
+ z.object({ legacyEvent: z.literal("site.lifecycle.changed") }).loose(),
1347
+ z.object({ legacyEvent: z.literal("site.analytics.ready") }).loose(),
1348
+ z.object({ legacyEvent: z.literal("site.indexing.ready") }).loose(),
1349
+ z.object({ legacyEvent: z.literal("site.auth.failed") }).loose()
1350
+ ]);
1351
+ const partnerWebhookEnvelopeSchema = z.object({
1352
+ contractVersion: z.literal(WEBHOOK_CONTRACT_VERSION),
1353
+ deliveryId: z.string().min(1),
1354
+ event: canonicalWebhookEventTypeSchema,
1355
+ partnerId: z.string().min(1),
1356
+ userId: z.string().nullable(),
1357
+ siteId: z.string().optional(),
1358
+ externalUserId: z.string().nullable().optional(),
1359
+ externalSiteId: z.string().nullable().optional(),
1360
+ lifecycleRevision: z.number().int(),
1361
+ occurredAt: z.iso.datetime(),
1362
+ data: partnerWebhookDataSchema
1363
+ }).loose();
1364
+ const partnerEndpointSchemas = {
1365
+ appUser: { response: gscdumpUserMeResponseSchema },
1366
+ appHealth: { response: gscdumpHealthResponseSchema },
1367
+ appSyncProgress: { response: gscdumpSyncProgressResponseSchema },
1368
+ appSyncJobs: { response: gscdumpSyncJobsResponseSchema },
1369
+ analyticsWhoami: { response: whoamiResponseSchema },
1370
+ analyticsSites: { response: z.array(siteListItemSchema) },
1371
+ analyticsCountries: { response: countriesResponseSchema },
1372
+ analyticsSearchAppearance: { response: searchAppearanceResponseSchema },
1373
+ analyticsSitemapHistory: { response: sitemapHistoryResponseSchema },
1374
+ analyticsSitemaps: { response: sitemapIndexSchema },
1375
+ analyticsInspectionHistory: { response: inspectionHistoryResponseSchema },
1376
+ analyticsInspections: { response: inspectionIndexSchema },
1377
+ analyticsRows: { response: gscRowQueryResponseSchema },
1378
+ analyticsRollup: { response: rollupEnvelopeSchema },
1379
+ analyticsBackfill: {
1380
+ body: backfillRangeSchema,
1381
+ response: backfillResponseSchema
1382
+ },
1383
+ analyticsIndexingUrls: { response: indexingUrlsResponseSchema },
1384
+ analyticsIndexingDiagnostics: { response: indexingDiagnosticsSchema },
1385
+ analyticsSitemapChanges: { response: sitemapChangesResponseSchema },
1386
+ analyticsAnalysisSources: { response: gscdumpAnalysisSourcesResponseSchema },
1387
+ analyticsSourceInfo: { response: sourceInfoResponseSchema },
1388
+ registerUser: {
1389
+ body: registerPartnerUserSchema,
1390
+ response: gscdumpUserRegistrationSchema
1391
+ },
1392
+ updateUserTokens: {
1393
+ body: updatePartnerUserTokensSchema,
1394
+ response: z.object({
1395
+ userId: z.string(),
1396
+ updated: z.boolean(),
1397
+ sites: z.array(gscdumpAvailableSiteSchema)
1398
+ }).loose()
1399
+ },
1400
+ getUserStatus: { response: gscdumpUserStatusSchema },
1401
+ getUserLifecycle: { response: partnerLifecycleResponseSchema },
1402
+ getUserSites: { response: z.object({ sites: z.array(gscdumpUserSiteSchema) }).loose() },
1403
+ getAvailableSites: { response: z.object({ sites: z.array(gscdumpAvailableSiteSchema) }).loose() },
1404
+ registerSite: {
1405
+ body: registerPartnerSiteSchema,
1406
+ response: gscdumpSiteRegistrationSchema
1407
+ },
1408
+ bulkRegisterSites: {
1409
+ body: bulkRegisterPartnerSitesSchema,
1410
+ response: bulkRegisterPartnerSitesResponseSchema
1411
+ },
1412
+ deleteUser: { response: gscdumpDeletePartnerUserResponseSchema },
1413
+ getAnalysisSources: { response: gscdumpAnalysisSourcesResponseSchema },
1414
+ getData: {
1415
+ state: builderStateSchema,
1416
+ options: dataQueryOptionsSchema,
1417
+ response: gscdumpDataResponseSchema
1418
+ },
1419
+ getDataDetail: {
1420
+ state: builderStateSchema,
1421
+ options: dataDetailOptionsSchema,
1422
+ response: gscdumpDataDetailResponseSchema
1423
+ },
1424
+ getAnalysis: {
1425
+ query: gscdumpAnalysisParamsSchema,
1426
+ response: gscdumpAnalysisResponseSchema
1427
+ },
1428
+ getSitemaps: { response: gscdumpSitemapsResponseSchema },
1429
+ getSitemapChanges: { response: gscdumpSitemapChangesResponseSchema },
1430
+ getIndexing: { response: gscdumpIndexingResponseSchema },
1431
+ getIndexingUrls: {
1432
+ query: indexingUrlsParamsSchema,
1433
+ response: gscdumpIndexingUrlsResponseSchema
1434
+ },
1435
+ getIndexingDiagnostics: { response: gscdumpIndexingDiagnosticsResponseSchema },
1436
+ getUserSettings: { response: gscdumpUserSettingsSchema },
1437
+ patchUserSettings: {
1438
+ body: gscdumpUserSettingsSchema.partial(),
1439
+ response: gscdumpUserSettingsSchema
1440
+ },
1441
+ recoverPermission: { response: gscdumpPermissionRecoverySchema },
1442
+ getTopAssociation: {
1443
+ query: gscdumpTopAssociationParamsSchema,
1444
+ response: gscdumpTopAssociationResponseSchema
1445
+ },
1446
+ getKeywordSparklines: {
1447
+ body: gscdumpKeywordSparklinesParamsSchema,
1448
+ response: gscdumpKeywordSparklinesResponseSchema
1449
+ },
1450
+ getQueryTrend: {
1451
+ query: gscdumpQueryTrendParamsSchema,
1452
+ response: gscdumpQueryTrendResponseSchema
1453
+ },
1454
+ getDateRangeInsight: {
1455
+ query: gscdumpDateRangeParamsSchema,
1456
+ response: unknownRecord
1457
+ },
1458
+ getCanonicalMismatches: { response: gscdumpCanonicalMismatchesResponseSchema },
1459
+ getIndexPercent: {
1460
+ query: gscdumpIndexPercentParamsSchema,
1461
+ response: gscdumpIndexPercentResponseSchema
1462
+ },
1463
+ getSiteReport: { response: gscdumpSiteReportResponseSchema },
1464
+ createTeam: {
1465
+ body: createPartnerTeamSchema,
1466
+ response: z.object({ team: gscdumpTeamRowSchema }).loose()
1467
+ },
1468
+ listTeamMembers: { response: z.object({ members: z.array(gscdumpTeamMemberRowSchema) }).loose() },
1469
+ addTeamMember: {
1470
+ body: addPartnerTeamMemberSchema,
1471
+ response: unknownRecord
1472
+ },
1473
+ bindSiteToTeam: {
1474
+ body: bindPartnerSiteTeamSchema,
1475
+ response: z.object({
1476
+ ok: z.literal(true),
1477
+ teamId: z.string().nullable()
1478
+ }).loose()
1479
+ },
1480
+ realtimeEvent: { message: partnerRealtimeEventSchema },
1481
+ webhook: {
1482
+ message: partnerWebhookEnvelopeSchema,
1483
+ legacyMessage: legacyWebhookPayloadSchema
1484
+ }
1485
+ };
1486
+ export { CANONICAL_WEBHOOK_EVENTS, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, LEGACY_WEBHOOK_EVENTS, VALID_WEBHOOK_EVENTS, WEBHOOK_CONTRACT_VERSION, WEBHOOK_CONTRACT_VERSION_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_EVENT_ALIASES, WEBHOOK_EVENT_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_TIMESTAMP_HEADER, accountNextActions, accountStatuses, addPartnerTeamMemberSchema, analyticsNextActions, analyticsRoutes, analyticsStatuses, authFailedWebhookPayloadSchema, backfillRangeSchema, backfillResponseSchema, bindPartnerSiteTeamSchema, builderStateSchema, bulkRegisterPartnerSitesResponseSchema, bulkRegisterPartnerSitesSchema, canonicalWebhookEventTypeSchema, countriesResponseSchema, countryRowSchema, createPartnerTeamSchema, dataDetailOptionsSchema, dataQueryOptionsSchema, gscApiRangeSchema, gscComparisonFilterSchema, gscRowQueryMetaSchema, gscRowQueryResponseSchema, gscdumpAnalysisParamsSchema, gscdumpAnalysisPresetSchema, gscdumpAnalysisResponseSchema, gscdumpAnalysisSourcesResponseSchema, gscdumpAvailableSiteSchema, gscdumpCanonicalMismatchesResponseSchema, gscdumpDataDetailResponseSchema, gscdumpDataResponseSchema, gscdumpDataRowSchema, gscdumpDateRangeParamsSchema, gscdumpDeletePartnerUserResponseSchema, gscdumpHealthResponseSchema, gscdumpIndexPercentParamsSchema, gscdumpIndexPercentResponseSchema, gscdumpIndexingDiagnosticsResponseSchema, gscdumpIndexingResponseSchema, gscdumpIndexingUrlsResponseSchema, gscdumpKeywordSparklinesParamsSchema, gscdumpKeywordSparklinesResponseSchema, gscdumpMetaSchema, gscdumpPermissionRecoverySchema, gscdumpQueryTrendParamsSchema, gscdumpQueryTrendResponseSchema, gscdumpSiteRegistrationSchema, gscdumpSiteReportResponseSchema, gscdumpSitemapChangesResponseSchema, gscdumpSitemapsResponseSchema, gscdumpSyncJobsResponseSchema, gscdumpSyncProgressResponseSchema, gscdumpTeamMemberRowSchema, gscdumpTeamRoleSchema, gscdumpTeamRowSchema, gscdumpTopAssociationParamsSchema, gscdumpTopAssociationResponseSchema, gscdumpTotalsSchema, gscdumpUserMeResponseSchema, gscdumpUserRegistrationSchema, gscdumpUserSettingsSchema, gscdumpUserSiteSchema, gscdumpUserStatusSchema, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingCompletedWebhookPayloadSchema, indexingDiagnosticsSchema, indexingIssueSchema, indexingNextActions, indexingStatuses, indexingUrlRowSchema, indexingUrlStatusSchema, indexingUrlsParamsSchema, indexingUrlsResponseSchema, inspectionHistoryRecordSchema, inspectionHistoryResponseSchema, inspectionIndexSchema, jobCompletedWebhookPayloadSchema, jobFailedWebhookPayloadSchema, legacyWebhookEventTypeSchema, legacyWebhookPayloadSchema, lifecycleErrorCodes, lifecycleErrorSchema, lifecycleProgressSchema, lifecycleWebhookEvents, parseGrantedScopes, partnerEndpointSchemas, partnerLifecycleAccountSchema, partnerLifecycleResponseSchema, partnerLifecycleSiteSchema, partnerRealtimeEventSchema, partnerRoutes, partnerWebhookDataSchema, partnerWebhookEnvelopeSchema, propertyNextActions, propertyStatuses, querySourceModes, registerPartnerSiteSchema, registerPartnerUserSchema, rollupEnvelopeSchema, searchAppearanceResponseSchema, searchAppearanceRowSchema, siteCompletedWebhookPayloadSchema, siteListItemSchema, sitemapChangesResponseSchema, sitemapHistoryRecordSchema, sitemapHistoryResponseSchema, sitemapIndexSchema, sitemapNextActions, sitemapStatuses, sourceInfoResponseSchema, updatePartnerUserTokensSchema, webhookEventTypeSchema, whoamiResponseSchema };