@gscdump/contracts 0.39.0 → 0.40.2

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, indexingNextActions, indexingStatuses, lifecycleErrorCodes, propertyNextActions, propertyStatuses, querySourceModes, sitemapNextActions, sitemapStatuses } from "../_chunks/onboarding.mjs";
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";
2
2
  import { z } from "zod";
3
3
  const HTTP_V1_SURFACES = [
4
4
  "partner",
@@ -839,19 +839,147 @@ function createGscdumpV1Protocol() {
839
839
  "googleNews"
840
840
  ]).optional()
841
841
  });
842
- const analyticsRowsResponse = defineSuccessResponse(defineResponseObject({ rows: z.array(z.record(z.string(), z.union([
842
+ const analyticsRowData = defineResponseObject({ rows: z.array(z.record(z.string(), z.union([
843
843
  z.string(),
844
844
  z.number(),
845
845
  z.boolean(),
846
846
  z.null()
847
- ]))) }), defineResponseObject({
847
+ ]))) });
848
+ const analyticsMeta = defineResponseObject({
848
849
  requestId: realtimeSchemas.publicRequestId,
849
850
  surface: z.literal("analytics"),
850
851
  version: z.literal("1.0"),
851
852
  sourceName: z.string().min(1),
852
853
  sourceKind: z.enum(["row", "sql"]),
853
854
  queryMs: z.number().nonnegative()
854
- }));
855
+ });
856
+ const analyticsRowsResponse = defineSuccessResponse(analyticsRowData, analyticsMeta);
857
+ const analyticsReportState = builderStateSchema.extend({ dimensions: z.array(z.enum(dimensions)).min(1) });
858
+ const analyticsListReportState = analyticsReportState.refine((state) => !state.dimensions.includes("date"), {
859
+ message: "List reports do not accept the date dimension.",
860
+ path: ["dimensions"]
861
+ });
862
+ const analyticsDetailReportState = analyticsReportState.refine((state) => state.dimensions.includes("date"), {
863
+ message: "Detail reports require the date dimension.",
864
+ path: ["dimensions"]
865
+ });
866
+ const analyticsReportRequest = z.strictObject({
867
+ state: analyticsListReportState,
868
+ comparison: analyticsListReportState.optional(),
869
+ filter: gscComparisonFilterSchema.optional()
870
+ });
871
+ const analyticsReportDetailRequest = z.strictObject({
872
+ state: analyticsDetailReportState,
873
+ comparison: analyticsDetailReportState.optional()
874
+ });
875
+ const analyticsReportData = defineResponseObject(gscdumpDataResponseSchema.shape);
876
+ const analyticsReportDetailData = defineResponseObject(gscdumpDataDetailResponseSchema.shape);
877
+ const analyticsReportResponse = defineSuccessResponse(analyticsReportData, analyticsMeta);
878
+ const analyticsReportDetailResponse = defineSuccessResponse(analyticsReportDetailData, analyticsMeta);
879
+ const integerQuery = (number, wirePattern) => z.union([number, z.string().regex(wirePattern)]);
880
+ const numericQuery = z.union([z.number(), z.string().regex(/^-?(?:\d+(?:\.\d+)?|\.\d+)$/)]);
881
+ const indexingSummaryQuery = z.strictObject({ days: integerQuery(z.number().int().min(1).max(90), /^(?:[1-9]|[1-8]\d|90)$/).optional() });
882
+ const indexingUrlsQuery = z.strictObject({
883
+ limit: integerQuery(z.number().int().min(1).max(500), /^(?:[1-9]|[1-9]\d|[1-4]\d{2}|500)$/).optional(),
884
+ offset: integerQuery(z.number().int().min(0), /^(?:0|[1-9]\d*)$/).optional(),
885
+ status: z.enum([
886
+ "indexed",
887
+ "not_indexed",
888
+ "pending"
889
+ ]).optional(),
890
+ issue: z.string().optional(),
891
+ search: z.string().optional(),
892
+ count: z.union([
893
+ z.literal(0),
894
+ z.literal(false),
895
+ z.literal("0"),
896
+ z.literal("false")
897
+ ]).optional()
898
+ });
899
+ const indexingDiagnosticsQuery = z.strictObject({
900
+ sampleIssues: z.union([z.string(), z.array(z.string())]).optional(),
901
+ sampleLimit: integerQuery(z.number().int().min(1).max(25), /^(?:[1-9]|1\d|2[0-5])$/).optional()
902
+ });
903
+ const sitemapChangesQuery = z.strictObject({ days: integerQuery(z.number().int().min(1).max(90), /^(?:[1-9]|[1-8]\d|90)$/).optional() });
904
+ const analysisBaseQueryShape = {
905
+ startDate: z.string().min(1),
906
+ endDate: z.string().min(1),
907
+ prevStartDate: z.string().min(1).optional(),
908
+ prevEndDate: z.string().min(1).optional(),
909
+ brandTerms: z.string().optional(),
910
+ limit: integerQuery(z.number().int().min(1).max(1e3), /^(?:[1-9]|[1-9]\d|[1-9]\d{2}|1000)$/).optional(),
911
+ offset: integerQuery(z.number().int().min(0), /^(?:0|[1-9]\d*)$/).optional(),
912
+ search: z.string().optional(),
913
+ minImpressions: numericQuery.optional(),
914
+ minPosition: numericQuery.optional(),
915
+ maxPosition: numericQuery.optional(),
916
+ maxCtr: numericQuery.optional(),
917
+ searchType: searchTypeSchema.optional()
918
+ };
919
+ const analysisQuery = z.strictObject({
920
+ ...analysisBaseQueryShape,
921
+ preset: gscdumpAnalysisPresetSchema
922
+ }).superRefine((value, ctx) => {
923
+ if ((value.preset === "brand-only" || value.preset === "non-brand") && !value.brandTerms?.trim()) ctx.addIssue({
924
+ code: "custom",
925
+ path: ["brandTerms"],
926
+ message: "brandTerms is required for brand/non-brand presets"
927
+ });
928
+ });
929
+ const analysisBundleQuery = z.strictObject({
930
+ ...analysisBaseQueryShape,
931
+ presets: z.union([z.array(gscdumpAnalysisPresetSchema).min(1).max(8), z.string().min(1)])
932
+ }).superRefine((value, ctx) => {
933
+ const presets = typeof value.presets === "string" ? value.presets.split(",").map((preset) => preset.trim()).filter(Boolean) : value.presets;
934
+ if (presets.length < 1 || presets.length > 8 || presets.some((preset) => !gscdumpAnalysisPresetSchema.safeParse(preset).success)) ctx.addIssue({
935
+ code: "custom",
936
+ path: ["presets"],
937
+ message: "presets must contain 1 to 8 supported presets"
938
+ });
939
+ if (presets.some((preset) => preset === "brand-only" || preset === "non-brand") && !value.brandTerms?.trim()) ctx.addIssue({
940
+ code: "custom",
941
+ path: ["brandTerms"],
942
+ message: "brandTerms is required for brand/non-brand presets"
943
+ });
944
+ if (presets.some((preset) => preset === "movers-rising" || preset === "movers-declining" || preset === "decay") && (!value.prevStartDate || !value.prevEndDate)) ctx.addIssue({
945
+ code: "custom",
946
+ path: ["prevStartDate"],
947
+ message: "Comparison presets require both previous-period dates"
948
+ });
949
+ });
950
+ const availableSitesQuery = z.strictObject({ refresh: z.union([
951
+ z.literal(true),
952
+ z.literal(1),
953
+ z.literal("true"),
954
+ z.literal("1")
955
+ ]).optional() });
956
+ const registerSiteRequest = registerPartnerSiteSchema.omit({
957
+ userId: true,
958
+ teamId: true
959
+ }).strict();
960
+ const indexingSummaryResponse = defineSuccessResponse(defineResponseObject(gscdumpIndexingResponseSchema.shape), partnerResponseMeta);
961
+ const indexingUrlsResponse = defineSuccessResponse(defineResponseObject(indexingUrlsResponseSchema.shape), partnerResponseMeta);
962
+ const indexingDiagnosticsResponse = defineSuccessResponse(defineResponseObject(gscdumpIndexingDiagnosticsResponseSchema.shape), partnerResponseMeta);
963
+ const sitemapsResponse = defineSuccessResponse(defineResponseObject(gscdumpSitemapsResponseSchema.shape), partnerResponseMeta);
964
+ const sitemapChangesResponse = defineSuccessResponse(defineResponseObject({
965
+ ...gscdumpSitemapChangesResponseSchema.shape,
966
+ summary: gscdumpSitemapChangesResponseSchema.shape.summary.unwrap()
967
+ }), partnerResponseMeta);
968
+ const analysisResponse = defineSuccessResponse(defineResponseObject(gscdumpAnalysisResponseSchema.shape), partnerResponseMeta);
969
+ const analysisBundleResponse = defineSuccessResponse(defineResponseObject(gscdumpAnalysisBundleResponseSchema.shape), partnerResponseMeta);
970
+ const availableSitesResponse = defineSuccessResponse(defineResponseObject({ sites: z.array(gscdumpAvailableSiteSchema) }), partnerResponseMeta);
971
+ const siteRegistrationResponse = defineSuccessResponse(defineResponseObject(gscdumpSiteRegistrationSchema.shape), partnerResponseMeta);
972
+ const siteDeletionResponse = defineSuccessResponse(defineResponseObject({
973
+ deleted: z.literal(true),
974
+ siteId: realtimeSchemas.publicSiteId,
975
+ siteUrl: z.string().min(1)
976
+ }), partnerResponseMeta);
977
+ const userRegistrationResponse = defineSuccessResponse(defineResponseObject(gscdumpUserRegistrationSchema.shape), partnerResponseMeta);
978
+ const userTokenUpdateResponse = defineSuccessResponse(defineResponseObject({
979
+ userId: realtimeSchemas.publicUserId,
980
+ updated: z.boolean(),
981
+ sites: z.array(gscdumpAvailableSiteSchema)
982
+ }), partnerResponseMeta);
855
983
  const responseStreamHead = defineResponseObject({
856
984
  streamId: realtimeSchemas.streamId,
857
985
  sequence: realtimeSchemas.sequence
@@ -879,6 +1007,24 @@ function createGscdumpV1Protocol() {
879
1007
  "internal_error",
880
1008
  "contract_violation"
881
1009
  ];
1010
+ const partnerSiteErrors = [
1011
+ "invalid_request",
1012
+ "unauthorized",
1013
+ "forbidden",
1014
+ "site_not_found",
1015
+ "rate_limited",
1016
+ "internal_error",
1017
+ "contract_violation"
1018
+ ];
1019
+ const partnerUserErrors = [
1020
+ "invalid_request",
1021
+ "unauthorized",
1022
+ "forbidden",
1023
+ "user_not_found",
1024
+ "rate_limited",
1025
+ "internal_error",
1026
+ "contract_violation"
1027
+ ];
882
1028
  const analyticsRowsErrors = [
883
1029
  "invalid_request",
884
1030
  "unauthorized",
@@ -901,149 +1047,1160 @@ function createGscdumpV1Protocol() {
901
1047
  name: "partner",
902
1048
  prefix: "/api/partner/v1",
903
1049
  version: "1.0",
904
- operations: { getUserLifecycle: defineHttpOperation({
905
- id: "partner.users.lifecycle.get",
906
- method: "GET",
907
- path: "/users/{userId}/lifecycle",
908
- visibility: "public",
909
- semantics: {
910
- kind: "query",
911
- sideEffects: "none",
912
- idempotent: true,
913
- retry: "idempotent",
914
- readConsistency: "primary"
915
- },
916
- auth: {
917
- credentials: ["user_key", "partner_key"],
918
- scopes: ["users:read"],
919
- ownership: [{
920
- credential: "user_key",
921
- rule: "self"
922
- }, {
923
- credential: "partner_key",
924
- rule: "linked_user"
925
- }]
926
- },
927
- request: {
928
- params: z.strictObject({ userId: realtimeSchemas.publicUserId }),
929
- query: null,
930
- headers: requestHeaders,
931
- body: null
932
- },
933
- responses: { 200: lifecycleResponse },
934
- errors: partnerUserLifecycleErrors,
935
- errorResponse: errorEnvelopeSchemas(partnerUserLifecycleErrors, realtimeSchemas.publicRequestId),
936
- resources: {
937
- reads: [{
938
- type: "partner.user",
939
- idFrom: "params.userId"
940
- }, {
941
- type: "user.sites",
942
- idFrom: "params.userId"
943
- }],
944
- changes: []
945
- },
946
- lifecycle: { introduced: "1.0.0" },
947
- docs: {
948
- summary: "Get user lifecycle",
949
- description: "Returns the authoritative lifecycle state for one visible user and their sites.",
950
- tags: ["Users"],
951
- examples: {
952
- request: { params: { userId: "u_01" } },
953
- response: {
954
- data: {
955
- userId: "u_01",
956
- partnerId: "p_01",
957
- currentTeamId: null,
958
- account: {
959
- status: "ready",
960
- grantedScopes: ["https://www.googleapis.com/auth/webmasters.readonly"],
961
- missingScopes: [],
962
- nextAction: "none"
1050
+ operations: {
1051
+ getUserLifecycle: defineHttpOperation({
1052
+ id: "partner.users.lifecycle.get",
1053
+ method: "GET",
1054
+ path: "/users/{userId}/lifecycle",
1055
+ visibility: "public",
1056
+ semantics: {
1057
+ kind: "query",
1058
+ sideEffects: "none",
1059
+ idempotent: true,
1060
+ retry: "idempotent",
1061
+ readConsistency: "primary"
1062
+ },
1063
+ auth: {
1064
+ credentials: ["user_key", "partner_key"],
1065
+ scopes: ["users:read"],
1066
+ ownership: [{
1067
+ credential: "user_key",
1068
+ rule: "self"
1069
+ }, {
1070
+ credential: "partner_key",
1071
+ rule: "linked_user"
1072
+ }]
1073
+ },
1074
+ request: {
1075
+ params: z.strictObject({ userId: realtimeSchemas.publicUserId }),
1076
+ query: null,
1077
+ headers: requestHeaders,
1078
+ body: null
1079
+ },
1080
+ responses: { 200: lifecycleResponse },
1081
+ errors: partnerUserLifecycleErrors,
1082
+ errorResponse: errorEnvelopeSchemas(partnerUserLifecycleErrors, realtimeSchemas.publicRequestId),
1083
+ resources: {
1084
+ reads: [{
1085
+ type: "partner.user",
1086
+ idFrom: "params.userId"
1087
+ }, {
1088
+ type: "user.sites",
1089
+ idFrom: "params.userId"
1090
+ }],
1091
+ changes: []
1092
+ },
1093
+ lifecycle: { introduced: "1.0.0" },
1094
+ docs: {
1095
+ summary: "Get user lifecycle",
1096
+ description: "Returns the authoritative lifecycle state for one visible user and their sites.",
1097
+ tags: ["Users"],
1098
+ examples: {
1099
+ request: { params: { userId: "u_01" } },
1100
+ response: {
1101
+ data: {
1102
+ userId: "u_01",
1103
+ partnerId: "p_01",
1104
+ currentTeamId: null,
1105
+ account: {
1106
+ status: "ready",
1107
+ grantedScopes: ["https://www.googleapis.com/auth/webmasters.readonly"],
1108
+ missingScopes: [],
1109
+ nextAction: "none"
1110
+ },
1111
+ sites: []
963
1112
  },
964
- sites: []
1113
+ meta: {
1114
+ requestId: "req_01",
1115
+ surface: "partner",
1116
+ version: "1.0"
1117
+ }
1118
+ }
1119
+ }
1120
+ }
1121
+ }),
1122
+ listAvailableSites: defineHttpOperation({
1123
+ id: "partner.users.sites.available.list",
1124
+ method: "GET",
1125
+ path: "/users/{userId}/available-sites",
1126
+ visibility: "public",
1127
+ semantics: {
1128
+ kind: "query",
1129
+ sideEffects: "none",
1130
+ idempotent: true,
1131
+ retry: "idempotent",
1132
+ readConsistency: "primary"
1133
+ },
1134
+ auth: {
1135
+ credentials: ["user_key", "partner_key"],
1136
+ scopes: ["sites:read"],
1137
+ ownership: [{
1138
+ credential: "user_key",
1139
+ rule: "self"
1140
+ }, {
1141
+ credential: "partner_key",
1142
+ rule: "linked_user"
1143
+ }]
1144
+ },
1145
+ request: {
1146
+ params: z.strictObject({ userId: realtimeSchemas.publicUserId }),
1147
+ query: availableSitesQuery,
1148
+ headers: requestHeaders,
1149
+ body: null
1150
+ },
1151
+ responses: { 200: availableSitesResponse },
1152
+ errors: partnerUserErrors,
1153
+ errorResponse: errorEnvelopeSchemas(partnerUserErrors, realtimeSchemas.publicRequestId),
1154
+ resources: {
1155
+ reads: [{
1156
+ type: "partner.user",
1157
+ idFrom: "params.userId"
1158
+ }, {
1159
+ type: "user.sites",
1160
+ idFrom: "params.userId"
1161
+ }],
1162
+ changes: []
1163
+ },
1164
+ lifecycle: { introduced: "1.0.0" },
1165
+ docs: {
1166
+ summary: "List available Search Console properties",
1167
+ description: "Lists the visible Google Search Console properties and their registration state.",
1168
+ tags: ["Sites"],
1169
+ examples: {
1170
+ request: {
1171
+ params: { userId: "u_01" },
1172
+ query: {}
965
1173
  },
966
- meta: {
967
- requestId: "req_01",
968
- surface: "partner",
969
- version: "1.0"
1174
+ response: {
1175
+ data: { sites: [] },
1176
+ meta: {
1177
+ requestId: "req_01",
1178
+ surface: "partner",
1179
+ version: "1.0"
1180
+ }
970
1181
  }
971
1182
  }
972
1183
  }
973
- }
974
- }) }
975
- });
976
- const analytics = defineHttpSurface({
977
- name: "analytics",
978
- prefix: "/api/analytics/v1",
979
- version: "1.0",
980
- operations: { queryRows: defineHttpOperation({
981
- id: "analytics.rows.query",
982
- method: "POST",
983
- path: "/sites/{siteId}/rows",
984
- visibility: "public",
985
- semantics: {
986
- kind: "query",
987
- sideEffects: "none",
988
- idempotent: true,
989
- retry: "idempotent",
990
- readConsistency: "primary"
991
- },
992
- auth: {
993
- credentials: ["user_key", "partner_key"],
994
- scopes: ["analytics:execute"],
995
- ownership: [{
996
- credential: "user_key",
997
- rule: "authorized_site"
998
- }, {
999
- credential: "partner_key",
1000
- rule: "authorized_site"
1001
- }]
1002
- },
1003
- request: {
1004
- params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1005
- query: null,
1006
- headers: requestHeaders,
1007
- body: analyticsRowsRequest
1008
- },
1009
- responses: { 200: analyticsRowsResponse },
1010
- errors: analyticsRowsErrors,
1011
- errorResponse: errorEnvelopeSchemas(analyticsRowsErrors, realtimeSchemas.publicRequestId),
1012
- resources: {
1013
- reads: [{
1014
- type: "site.analytics",
1015
- idFrom: "params.siteId"
1016
- }],
1017
- changes: []
1018
- },
1019
- lifecycle: { introduced: "1.0.0" },
1020
- docs: {
1021
- summary: "Query analytics rows",
1022
- description: "Executes an idempotent primary-consistent analytics row query.",
1023
- tags: ["Analytics rows"],
1024
- examples: {
1025
- request: {
1026
- params: { siteId: "s_01" },
1027
- body: {
1028
- dimensions: ["query"],
1029
- metrics: ["clicks", "impressions"],
1030
- rowLimit: 100
1184
+ }),
1185
+ createSite: defineHttpOperation({
1186
+ id: "partner.users.sites.create",
1187
+ method: "POST",
1188
+ path: "/users/{userId}/sites",
1189
+ visibility: "public",
1190
+ semantics: {
1191
+ kind: "mutation",
1192
+ sideEffects: "state",
1193
+ idempotent: true,
1194
+ retry: "idempotent",
1195
+ readConsistency: null
1196
+ },
1197
+ auth: {
1198
+ credentials: ["user_key", "partner_key"],
1199
+ scopes: ["sites:write"],
1200
+ ownership: [{
1201
+ credential: "user_key",
1202
+ rule: "self"
1203
+ }, {
1204
+ credential: "partner_key",
1205
+ rule: "linked_user"
1206
+ }]
1207
+ },
1208
+ request: {
1209
+ params: z.strictObject({ userId: realtimeSchemas.publicUserId }),
1210
+ query: null,
1211
+ headers: requestHeaders,
1212
+ body: registerSiteRequest
1213
+ },
1214
+ responses: { 200: siteRegistrationResponse },
1215
+ errors: partnerUserErrors,
1216
+ errorResponse: errorEnvelopeSchemas(partnerUserErrors, realtimeSchemas.publicRequestId),
1217
+ resources: {
1218
+ reads: [{
1219
+ type: "partner.user",
1220
+ idFrom: "params.userId"
1221
+ }],
1222
+ changes: [{
1223
+ type: "site.registration",
1224
+ idFrom: "params.userId"
1225
+ }]
1226
+ },
1227
+ lifecycle: { introduced: "1.0.0" },
1228
+ docs: {
1229
+ summary: "Register a site",
1230
+ description: "Registers one Search Console property for an authorized user.",
1231
+ tags: ["Sites"],
1232
+ examples: {
1233
+ request: {
1234
+ params: { userId: "u_01" },
1235
+ body: { siteUrl: "sc-domain:example.com" }
1236
+ },
1237
+ response: {
1238
+ data: {
1239
+ siteId: "s_01",
1240
+ status: "pending"
1241
+ },
1242
+ meta: {
1243
+ requestId: "req_01",
1244
+ surface: "partner",
1245
+ version: "1.0"
1246
+ }
1247
+ }
1248
+ }
1249
+ }
1250
+ }),
1251
+ createUser: defineHttpOperation({
1252
+ id: "partner.users.create",
1253
+ method: "POST",
1254
+ path: "/users",
1255
+ visibility: "public",
1256
+ semantics: {
1257
+ kind: "mutation",
1258
+ sideEffects: "state",
1259
+ idempotent: true,
1260
+ retry: "idempotent",
1261
+ readConsistency: null
1262
+ },
1263
+ auth: {
1264
+ credentials: ["partner_key"],
1265
+ scopes: ["users:write"],
1266
+ ownership: [{
1267
+ credential: "partner_key",
1268
+ rule: "partner_tenant"
1269
+ }]
1270
+ },
1271
+ request: {
1272
+ params: null,
1273
+ query: null,
1274
+ headers: requestHeaders,
1275
+ body: registerPartnerUserSchema.strict()
1276
+ },
1277
+ responses: { 200: userRegistrationResponse },
1278
+ errors: partnerUserErrors,
1279
+ errorResponse: errorEnvelopeSchemas(partnerUserErrors, realtimeSchemas.publicRequestId),
1280
+ resources: {
1281
+ reads: [],
1282
+ changes: [{
1283
+ type: "partner.user",
1284
+ idFrom: "principal.id"
1285
+ }]
1286
+ },
1287
+ lifecycle: { introduced: "1.0.0" },
1288
+ docs: {
1289
+ summary: "Register a partner user",
1290
+ description: "Creates or updates a user owned by the authenticated partner tenant.",
1291
+ tags: ["Users"],
1292
+ examples: {
1293
+ request: { body: {
1294
+ userGoogleId: "google_01",
1295
+ userEmail: "owner@example.com",
1296
+ accessToken: "token",
1297
+ refreshToken: "refresh"
1298
+ } },
1299
+ response: {
1300
+ data: {
1301
+ userId: "u_01",
1302
+ status: "provisioning"
1303
+ },
1304
+ meta: {
1305
+ requestId: "req_01",
1306
+ surface: "partner",
1307
+ version: "1.0"
1308
+ }
1031
1309
  }
1032
- },
1033
- response: {
1034
- data: { rows: [] },
1035
- meta: {
1036
- requestId: "req_01",
1037
- surface: "analytics",
1038
- version: "1.0",
1039
- sourceName: "primary",
1040
- sourceKind: "sql",
1041
- queryMs: 12
1310
+ }
1311
+ }
1312
+ }),
1313
+ updateUserTokens: defineHttpOperation({
1314
+ id: "partner.users.tokens.update",
1315
+ method: "PATCH",
1316
+ path: "/users/{userId}/tokens",
1317
+ visibility: "public",
1318
+ semantics: {
1319
+ kind: "mutation",
1320
+ sideEffects: "state",
1321
+ idempotent: true,
1322
+ retry: "idempotent",
1323
+ readConsistency: null
1324
+ },
1325
+ auth: {
1326
+ credentials: ["partner_key"],
1327
+ scopes: ["users:write"],
1328
+ ownership: [{
1329
+ credential: "partner_key",
1330
+ rule: "linked_user"
1331
+ }]
1332
+ },
1333
+ request: {
1334
+ params: z.strictObject({ userId: realtimeSchemas.publicUserId }),
1335
+ query: null,
1336
+ headers: requestHeaders,
1337
+ body: updatePartnerUserTokensSchema.strict()
1338
+ },
1339
+ responses: { 200: userTokenUpdateResponse },
1340
+ errors: partnerUserErrors,
1341
+ errorResponse: errorEnvelopeSchemas(partnerUserErrors, realtimeSchemas.publicRequestId),
1342
+ resources: {
1343
+ reads: [{
1344
+ type: "partner.user",
1345
+ idFrom: "params.userId"
1346
+ }],
1347
+ changes: [{
1348
+ type: "partner.user",
1349
+ idFrom: "params.userId"
1350
+ }]
1351
+ },
1352
+ lifecycle: { introduced: "1.0.0" },
1353
+ docs: {
1354
+ summary: "Update user OAuth tokens",
1355
+ description: "Replaces the Google OAuth grant for a partner-linked user.",
1356
+ tags: ["Users"],
1357
+ examples: {
1358
+ request: {
1359
+ params: { userId: "u_01" },
1360
+ body: {
1361
+ accessToken: "token",
1362
+ refreshToken: "refresh"
1363
+ }
1364
+ },
1365
+ response: {
1366
+ data: {
1367
+ userId: "u_01",
1368
+ updated: true,
1369
+ sites: []
1370
+ },
1371
+ meta: {
1372
+ requestId: "req_01",
1373
+ surface: "partner",
1374
+ version: "1.0"
1375
+ }
1042
1376
  }
1043
1377
  }
1044
1378
  }
1045
- }
1046
- }) }
1379
+ }),
1380
+ getSiteIndexing: defineHttpOperation({
1381
+ id: "partner.sites.indexing.get",
1382
+ method: "GET",
1383
+ path: "/sites/{siteId}/indexing",
1384
+ visibility: "public",
1385
+ semantics: {
1386
+ kind: "query",
1387
+ sideEffects: "none",
1388
+ idempotent: true,
1389
+ retry: "idempotent",
1390
+ readConsistency: "primary"
1391
+ },
1392
+ auth: {
1393
+ credentials: ["user_key", "partner_key"],
1394
+ scopes: ["indexing:read"],
1395
+ ownership: [{
1396
+ credential: "user_key",
1397
+ rule: "authorized_site"
1398
+ }, {
1399
+ credential: "partner_key",
1400
+ rule: "authorized_site"
1401
+ }]
1402
+ },
1403
+ request: {
1404
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1405
+ query: indexingSummaryQuery,
1406
+ headers: requestHeaders,
1407
+ body: null
1408
+ },
1409
+ responses: { 200: indexingSummaryResponse },
1410
+ errors: partnerSiteErrors,
1411
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1412
+ resources: {
1413
+ reads: [{
1414
+ type: "site.indexing",
1415
+ idFrom: "params.siteId"
1416
+ }],
1417
+ changes: []
1418
+ },
1419
+ lifecycle: { introduced: "1.0.0" },
1420
+ docs: {
1421
+ summary: "Get site indexing summary",
1422
+ description: "Returns indexing coverage, trend, and inspection signal totals.",
1423
+ tags: ["Indexing"],
1424
+ examples: {
1425
+ request: {
1426
+ params: { siteId: "s_01" },
1427
+ query: { days: 28 }
1428
+ },
1429
+ response: {
1430
+ data: {
1431
+ trend: [],
1432
+ summary: {
1433
+ totalUrls: 0,
1434
+ indexed: 0,
1435
+ notIndexed: 0,
1436
+ pending: 0,
1437
+ indexedPercent: 0,
1438
+ oldestCheck: null,
1439
+ newestCheck: null,
1440
+ change7d: null,
1441
+ change28d: null,
1442
+ signals: {
1443
+ mobilePass: 0,
1444
+ mobileFail: 0,
1445
+ mobileUnspecified: 0,
1446
+ richResultsPass: 0,
1447
+ richResultsFail: 0,
1448
+ richResultTypes: [],
1449
+ crawlingMobile: 0,
1450
+ crawlingDesktop: 0
1451
+ }
1452
+ },
1453
+ meta: {
1454
+ siteUrl: "sc-domain:example.com",
1455
+ syncStatus: "synced",
1456
+ indexingStatus: "complete",
1457
+ indexingProgress: 100,
1458
+ sitemapTotal: 0,
1459
+ inspectedCount: 0,
1460
+ noSitemapsSubmitted: false,
1461
+ sitemapsPending: false
1462
+ }
1463
+ },
1464
+ meta: {
1465
+ requestId: "req_01",
1466
+ surface: "partner",
1467
+ version: "1.0"
1468
+ }
1469
+ }
1470
+ }
1471
+ }
1472
+ }),
1473
+ listSiteIndexingUrls: defineHttpOperation({
1474
+ id: "partner.sites.indexing.urls.list",
1475
+ method: "GET",
1476
+ path: "/sites/{siteId}/indexing/urls",
1477
+ visibility: "public",
1478
+ semantics: {
1479
+ kind: "query",
1480
+ sideEffects: "none",
1481
+ idempotent: true,
1482
+ retry: "idempotent",
1483
+ readConsistency: "primary"
1484
+ },
1485
+ auth: {
1486
+ credentials: ["user_key", "partner_key"],
1487
+ scopes: ["indexing:read"],
1488
+ ownership: [{
1489
+ credential: "user_key",
1490
+ rule: "authorized_site"
1491
+ }, {
1492
+ credential: "partner_key",
1493
+ rule: "authorized_site"
1494
+ }]
1495
+ },
1496
+ request: {
1497
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1498
+ query: indexingUrlsQuery,
1499
+ headers: requestHeaders,
1500
+ body: null
1501
+ },
1502
+ responses: { 200: indexingUrlsResponse },
1503
+ errors: partnerSiteErrors,
1504
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1505
+ resources: {
1506
+ reads: [{
1507
+ type: "site.indexing",
1508
+ idFrom: "params.siteId"
1509
+ }],
1510
+ changes: []
1511
+ },
1512
+ lifecycle: { introduced: "1.0.0" },
1513
+ docs: {
1514
+ summary: "List indexed URLs",
1515
+ description: "Returns the filtered URL-inspection index with pagination metadata.",
1516
+ tags: ["Indexing"],
1517
+ examples: {
1518
+ request: {
1519
+ params: { siteId: "s_01" },
1520
+ query: {
1521
+ limit: 100,
1522
+ offset: 0
1523
+ }
1524
+ },
1525
+ response: {
1526
+ data: {
1527
+ urls: [],
1528
+ pagination: {
1529
+ total: 0,
1530
+ limit: 100,
1531
+ offset: 0,
1532
+ hasMore: false
1533
+ },
1534
+ meta: {
1535
+ siteUrl: "sc-domain:example.com",
1536
+ status: "all",
1537
+ issue: null
1538
+ }
1539
+ },
1540
+ meta: {
1541
+ requestId: "req_01",
1542
+ surface: "partner",
1543
+ version: "1.0"
1544
+ }
1545
+ }
1546
+ }
1547
+ }
1548
+ }),
1549
+ getSiteIndexingDiagnostics: defineHttpOperation({
1550
+ id: "partner.sites.indexing.diagnostics.get",
1551
+ method: "GET",
1552
+ path: "/sites/{siteId}/indexing/diagnostics",
1553
+ visibility: "public",
1554
+ semantics: {
1555
+ kind: "query",
1556
+ sideEffects: "none",
1557
+ idempotent: true,
1558
+ retry: "idempotent",
1559
+ readConsistency: "primary"
1560
+ },
1561
+ auth: {
1562
+ credentials: ["user_key", "partner_key"],
1563
+ scopes: ["indexing:read"],
1564
+ ownership: [{
1565
+ credential: "user_key",
1566
+ rule: "authorized_site"
1567
+ }, {
1568
+ credential: "partner_key",
1569
+ rule: "authorized_site"
1570
+ }]
1571
+ },
1572
+ request: {
1573
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1574
+ query: indexingDiagnosticsQuery,
1575
+ headers: requestHeaders,
1576
+ body: null
1577
+ },
1578
+ responses: { 200: indexingDiagnosticsResponse },
1579
+ errors: partnerSiteErrors,
1580
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1581
+ resources: {
1582
+ reads: [{
1583
+ type: "site.indexing",
1584
+ idFrom: "params.siteId"
1585
+ }],
1586
+ changes: []
1587
+ },
1588
+ lifecycle: { introduced: "1.0.0" },
1589
+ docs: {
1590
+ summary: "Get indexing diagnostics",
1591
+ description: "Returns indexing issue groups and optional URL samples.",
1592
+ tags: ["Indexing"],
1593
+ examples: {
1594
+ request: {
1595
+ params: { siteId: "s_01" },
1596
+ query: {}
1597
+ },
1598
+ response: {
1599
+ data: {
1600
+ summary: {
1601
+ totalUrls: 0,
1602
+ indexed: 0,
1603
+ indexedPercent: 0
1604
+ },
1605
+ issues: [],
1606
+ meta: { siteUrl: "sc-domain:example.com" }
1607
+ },
1608
+ meta: {
1609
+ requestId: "req_01",
1610
+ surface: "partner",
1611
+ version: "1.0"
1612
+ }
1613
+ }
1614
+ }
1615
+ }
1616
+ }),
1617
+ getSiteSitemaps: defineHttpOperation({
1618
+ id: "partner.sites.sitemaps.get",
1619
+ method: "GET",
1620
+ path: "/sites/{siteId}/sitemaps",
1621
+ visibility: "public",
1622
+ semantics: {
1623
+ kind: "query",
1624
+ sideEffects: "none",
1625
+ idempotent: true,
1626
+ retry: "idempotent",
1627
+ readConsistency: "primary"
1628
+ },
1629
+ auth: {
1630
+ credentials: ["user_key", "partner_key"],
1631
+ scopes: ["sitemaps:read"],
1632
+ ownership: [{
1633
+ credential: "user_key",
1634
+ rule: "authorized_site"
1635
+ }, {
1636
+ credential: "partner_key",
1637
+ rule: "authorized_site"
1638
+ }]
1639
+ },
1640
+ request: {
1641
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1642
+ query: null,
1643
+ headers: requestHeaders,
1644
+ body: null
1645
+ },
1646
+ responses: { 200: sitemapsResponse },
1647
+ errors: partnerSiteErrors,
1648
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1649
+ resources: {
1650
+ reads: [{
1651
+ type: "site.sitemaps",
1652
+ idFrom: "params.siteId"
1653
+ }],
1654
+ changes: []
1655
+ },
1656
+ lifecycle: { introduced: "1.0.0" },
1657
+ docs: {
1658
+ summary: "Get sitemap snapshot",
1659
+ description: "Returns registered sitemaps and their aggregate and per-sitemap history.",
1660
+ tags: ["Sitemaps"],
1661
+ examples: {
1662
+ request: { params: { siteId: "s_01" } },
1663
+ response: {
1664
+ data: {
1665
+ sitemaps: [],
1666
+ history: [],
1667
+ perSitemapHistory: {},
1668
+ meta: {
1669
+ siteUrl: "sc-domain:example.com",
1670
+ gscPropertyUrl: "sc-domain:example.com",
1671
+ syncStatus: "synced"
1672
+ }
1673
+ },
1674
+ meta: {
1675
+ requestId: "req_01",
1676
+ surface: "partner",
1677
+ version: "1.0"
1678
+ }
1679
+ }
1680
+ }
1681
+ }
1682
+ }),
1683
+ getSiteSitemapChanges: defineHttpOperation({
1684
+ id: "partner.sites.sitemaps.changes.get",
1685
+ method: "GET",
1686
+ path: "/sites/{siteId}/sitemaps/changes",
1687
+ visibility: "public",
1688
+ semantics: {
1689
+ kind: "query",
1690
+ sideEffects: "none",
1691
+ idempotent: true,
1692
+ retry: "idempotent",
1693
+ readConsistency: "primary"
1694
+ },
1695
+ auth: {
1696
+ credentials: ["user_key", "partner_key"],
1697
+ scopes: ["sitemaps:read"],
1698
+ ownership: [{
1699
+ credential: "user_key",
1700
+ rule: "authorized_site"
1701
+ }, {
1702
+ credential: "partner_key",
1703
+ rule: "authorized_site"
1704
+ }]
1705
+ },
1706
+ request: {
1707
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1708
+ query: sitemapChangesQuery,
1709
+ headers: requestHeaders,
1710
+ body: null
1711
+ },
1712
+ responses: { 200: sitemapChangesResponse },
1713
+ errors: partnerSiteErrors,
1714
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1715
+ resources: {
1716
+ reads: [{
1717
+ type: "site.sitemaps",
1718
+ idFrom: "params.siteId"
1719
+ }],
1720
+ changes: []
1721
+ },
1722
+ lifecycle: { introduced: "1.0.0" },
1723
+ docs: {
1724
+ summary: "Get sitemap URL changes",
1725
+ description: "Returns recently added and removed sitemap URLs for the requested window.",
1726
+ tags: ["Sitemaps"],
1727
+ examples: {
1728
+ request: {
1729
+ params: { siteId: "s_01" },
1730
+ query: { days: 28 }
1731
+ },
1732
+ response: {
1733
+ data: {
1734
+ added: [],
1735
+ removed: [],
1736
+ summary: {
1737
+ totalAdded: 0,
1738
+ totalRemoved: 0,
1739
+ period: { days: 28 }
1740
+ }
1741
+ },
1742
+ meta: {
1743
+ requestId: "req_01",
1744
+ surface: "partner",
1745
+ version: "1.0"
1746
+ }
1747
+ }
1748
+ }
1749
+ }
1750
+ }),
1751
+ getSiteAnalysis: defineHttpOperation({
1752
+ id: "partner.sites.analysis.get",
1753
+ method: "GET",
1754
+ path: "/sites/{siteId}/analysis",
1755
+ visibility: "public",
1756
+ semantics: {
1757
+ kind: "query",
1758
+ sideEffects: "none",
1759
+ idempotent: true,
1760
+ retry: "idempotent",
1761
+ readConsistency: "primary"
1762
+ },
1763
+ auth: {
1764
+ credentials: ["user_key", "partner_key"],
1765
+ scopes: ["analytics:execute"],
1766
+ ownership: [{
1767
+ credential: "user_key",
1768
+ rule: "authorized_site"
1769
+ }, {
1770
+ credential: "partner_key",
1771
+ rule: "authorized_site"
1772
+ }]
1773
+ },
1774
+ request: {
1775
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1776
+ query: analysisQuery,
1777
+ headers: requestHeaders,
1778
+ body: null
1779
+ },
1780
+ responses: { 200: analysisResponse },
1781
+ errors: partnerSiteErrors,
1782
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1783
+ resources: {
1784
+ reads: [{
1785
+ type: "site.analytics",
1786
+ idFrom: "params.siteId"
1787
+ }],
1788
+ changes: []
1789
+ },
1790
+ lifecycle: { introduced: "1.0.0" },
1791
+ docs: {
1792
+ summary: "Run an analysis preset",
1793
+ description: "Runs one validated analysis preset for an analytics window.",
1794
+ tags: ["Analysis"],
1795
+ examples: {
1796
+ request: {
1797
+ params: { siteId: "s_01" },
1798
+ query: {
1799
+ preset: "opportunity",
1800
+ startDate: "2026-06-01",
1801
+ endDate: "2026-06-30"
1802
+ }
1803
+ },
1804
+ response: {
1805
+ data: {
1806
+ preset: "opportunity",
1807
+ keywords: [],
1808
+ totalCount: 0,
1809
+ meta: {
1810
+ siteUrl: "sc-domain:example.com",
1811
+ params: {
1812
+ startDate: "2026-06-01",
1813
+ endDate: "2026-06-30"
1814
+ }
1815
+ }
1816
+ },
1817
+ meta: {
1818
+ requestId: "req_01",
1819
+ surface: "partner",
1820
+ version: "1.0"
1821
+ }
1822
+ }
1823
+ }
1824
+ }
1825
+ }),
1826
+ getSiteAnalysisBundle: defineHttpOperation({
1827
+ id: "partner.sites.analysis.bundle.get",
1828
+ method: "GET",
1829
+ path: "/sites/{siteId}/analysis/bundle",
1830
+ visibility: "public",
1831
+ semantics: {
1832
+ kind: "query",
1833
+ sideEffects: "none",
1834
+ idempotent: true,
1835
+ retry: "idempotent",
1836
+ readConsistency: "primary"
1837
+ },
1838
+ auth: {
1839
+ credentials: ["user_key", "partner_key"],
1840
+ scopes: ["analytics:execute"],
1841
+ ownership: [{
1842
+ credential: "user_key",
1843
+ rule: "authorized_site"
1844
+ }, {
1845
+ credential: "partner_key",
1846
+ rule: "authorized_site"
1847
+ }]
1848
+ },
1849
+ request: {
1850
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1851
+ query: analysisBundleQuery,
1852
+ headers: requestHeaders,
1853
+ body: null
1854
+ },
1855
+ responses: { 200: analysisBundleResponse },
1856
+ errors: partnerSiteErrors,
1857
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1858
+ resources: {
1859
+ reads: [{
1860
+ type: "site.analytics",
1861
+ idFrom: "params.siteId"
1862
+ }],
1863
+ changes: []
1864
+ },
1865
+ lifecycle: { introduced: "1.0.0" },
1866
+ docs: {
1867
+ summary: "Run an analysis bundle",
1868
+ description: "Runs several validated presets against one shared analytics pool.",
1869
+ tags: ["Analysis"],
1870
+ examples: {
1871
+ request: {
1872
+ params: { siteId: "s_01" },
1873
+ query: {
1874
+ presets: ["opportunity"],
1875
+ startDate: "2026-06-01",
1876
+ endDate: "2026-06-30"
1877
+ }
1878
+ },
1879
+ response: {
1880
+ data: {
1881
+ bundle: {},
1882
+ meta: {
1883
+ siteUrl: "sc-domain:example.com",
1884
+ params: {
1885
+ startDate: "2026-06-01",
1886
+ endDate: "2026-06-30"
1887
+ }
1888
+ }
1889
+ },
1890
+ meta: {
1891
+ requestId: "req_01",
1892
+ surface: "partner",
1893
+ version: "1.0"
1894
+ }
1895
+ }
1896
+ }
1897
+ }
1898
+ }),
1899
+ deleteSite: defineHttpOperation({
1900
+ id: "partner.sites.delete",
1901
+ method: "DELETE",
1902
+ path: "/sites/{siteId}",
1903
+ visibility: "public",
1904
+ semantics: {
1905
+ kind: "mutation",
1906
+ sideEffects: "state",
1907
+ idempotent: true,
1908
+ retry: "idempotent",
1909
+ readConsistency: null
1910
+ },
1911
+ auth: {
1912
+ credentials: ["user_key", "partner_key"],
1913
+ scopes: ["sites:write"],
1914
+ ownership: [{
1915
+ credential: "user_key",
1916
+ rule: "authorized_site"
1917
+ }, {
1918
+ credential: "partner_key",
1919
+ rule: "authorized_site"
1920
+ }]
1921
+ },
1922
+ request: {
1923
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1924
+ query: null,
1925
+ headers: requestHeaders,
1926
+ body: null
1927
+ },
1928
+ responses: { 200: siteDeletionResponse },
1929
+ errors: partnerSiteErrors,
1930
+ errorResponse: errorEnvelopeSchemas(partnerSiteErrors, realtimeSchemas.publicRequestId),
1931
+ resources: {
1932
+ reads: [{
1933
+ type: "site.registration",
1934
+ idFrom: "params.siteId"
1935
+ }],
1936
+ changes: [{
1937
+ type: "site.registration",
1938
+ idFrom: "params.siteId"
1939
+ }, {
1940
+ type: "site.lifecycle",
1941
+ idFrom: "params.siteId"
1942
+ }]
1943
+ },
1944
+ lifecycle: { introduced: "1.0.0" },
1945
+ docs: {
1946
+ summary: "Delete a site registration",
1947
+ description: "Removes the site registration and queued work while retaining the user data store.",
1948
+ tags: ["Sites"],
1949
+ examples: {
1950
+ request: { params: { siteId: "s_01" } },
1951
+ response: {
1952
+ data: {
1953
+ deleted: true,
1954
+ siteId: "s_01",
1955
+ siteUrl: "example.com"
1956
+ },
1957
+ meta: {
1958
+ requestId: "req_01",
1959
+ surface: "partner",
1960
+ version: "1.0"
1961
+ }
1962
+ }
1963
+ }
1964
+ }
1965
+ })
1966
+ }
1967
+ });
1968
+ const analytics = defineHttpSurface({
1969
+ name: "analytics",
1970
+ prefix: "/api/analytics/v1",
1971
+ version: "1.0",
1972
+ operations: {
1973
+ queryRows: defineHttpOperation({
1974
+ id: "analytics.rows.query",
1975
+ method: "POST",
1976
+ path: "/sites/{siteId}/rows",
1977
+ visibility: "public",
1978
+ semantics: {
1979
+ kind: "query",
1980
+ sideEffects: "none",
1981
+ idempotent: true,
1982
+ retry: "idempotent",
1983
+ readConsistency: "primary"
1984
+ },
1985
+ auth: {
1986
+ credentials: ["user_key", "partner_key"],
1987
+ scopes: ["analytics:execute"],
1988
+ ownership: [{
1989
+ credential: "user_key",
1990
+ rule: "authorized_site"
1991
+ }, {
1992
+ credential: "partner_key",
1993
+ rule: "authorized_site"
1994
+ }]
1995
+ },
1996
+ request: {
1997
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
1998
+ query: null,
1999
+ headers: requestHeaders,
2000
+ body: analyticsRowsRequest
2001
+ },
2002
+ responses: { 200: analyticsRowsResponse },
2003
+ errors: analyticsRowsErrors,
2004
+ errorResponse: errorEnvelopeSchemas(analyticsRowsErrors, realtimeSchemas.publicRequestId),
2005
+ resources: {
2006
+ reads: [{
2007
+ type: "site.analytics",
2008
+ idFrom: "params.siteId"
2009
+ }],
2010
+ changes: []
2011
+ },
2012
+ lifecycle: { introduced: "1.0.0" },
2013
+ docs: {
2014
+ summary: "Query analytics rows",
2015
+ description: "Executes an idempotent primary-consistent analytics row query.",
2016
+ tags: ["Analytics rows"],
2017
+ examples: {
2018
+ request: {
2019
+ params: { siteId: "s_01" },
2020
+ body: {
2021
+ dimensions: ["query"],
2022
+ metrics: ["clicks", "impressions"],
2023
+ rowLimit: 100
2024
+ }
2025
+ },
2026
+ response: {
2027
+ data: { rows: [] },
2028
+ meta: {
2029
+ requestId: "req_01",
2030
+ surface: "analytics",
2031
+ version: "1.0",
2032
+ sourceName: "primary",
2033
+ sourceKind: "sql",
2034
+ queryMs: 12
2035
+ }
2036
+ }
2037
+ }
2038
+ }
2039
+ }),
2040
+ queryReport: defineHttpOperation({
2041
+ id: "analytics.reports.query",
2042
+ method: "POST",
2043
+ path: "/sites/{siteId}/reports",
2044
+ visibility: "public",
2045
+ semantics: {
2046
+ kind: "query",
2047
+ sideEffects: "none",
2048
+ idempotent: true,
2049
+ retry: "idempotent",
2050
+ readConsistency: "primary"
2051
+ },
2052
+ auth: {
2053
+ credentials: ["user_key", "partner_key"],
2054
+ scopes: ["analytics:execute"],
2055
+ ownership: [{
2056
+ credential: "user_key",
2057
+ rule: "authorized_site"
2058
+ }, {
2059
+ credential: "partner_key",
2060
+ rule: "authorized_site"
2061
+ }]
2062
+ },
2063
+ request: {
2064
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2065
+ query: null,
2066
+ headers: requestHeaders,
2067
+ body: analyticsReportRequest
2068
+ },
2069
+ responses: { 200: analyticsReportResponse },
2070
+ errors: analyticsRowsErrors,
2071
+ errorResponse: errorEnvelopeSchemas(analyticsRowsErrors, realtimeSchemas.publicRequestId),
2072
+ resources: {
2073
+ reads: [{
2074
+ type: "site.analytics",
2075
+ idFrom: "params.siteId"
2076
+ }],
2077
+ changes: []
2078
+ },
2079
+ lifecycle: { introduced: "1.0.0" },
2080
+ docs: {
2081
+ summary: "Query an analytics report",
2082
+ description: "Returns the hosted analytics list report with totals, comparison fields, and sync metadata.",
2083
+ tags: ["Analytics reports"],
2084
+ examples: {
2085
+ request: {
2086
+ params: { siteId: "s_01" },
2087
+ body: { state: {
2088
+ dimensions: ["query"],
2089
+ searchType: "web"
2090
+ } }
2091
+ },
2092
+ response: {
2093
+ data: {
2094
+ rows: [],
2095
+ totalCount: 0,
2096
+ totals: {
2097
+ clicks: 0,
2098
+ impressions: 0,
2099
+ ctr: 0,
2100
+ position: 0
2101
+ },
2102
+ meta: {
2103
+ siteUrl: "sc-domain:example.com",
2104
+ syncStatus: "synced",
2105
+ newestDateSynced: null,
2106
+ oldestDateSynced: null,
2107
+ dataDelay: "0 days"
2108
+ }
2109
+ },
2110
+ meta: {
2111
+ requestId: "req_01",
2112
+ surface: "analytics",
2113
+ version: "1.0",
2114
+ sourceName: "hosted-report",
2115
+ sourceKind: "sql",
2116
+ queryMs: 12
2117
+ }
2118
+ }
2119
+ }
2120
+ }
2121
+ }),
2122
+ queryReportDetail: defineHttpOperation({
2123
+ id: "analytics.reports.detail.query",
2124
+ method: "POST",
2125
+ path: "/sites/{siteId}/reports/detail",
2126
+ visibility: "public",
2127
+ semantics: {
2128
+ kind: "query",
2129
+ sideEffects: "none",
2130
+ idempotent: true,
2131
+ retry: "idempotent",
2132
+ readConsistency: "primary"
2133
+ },
2134
+ auth: {
2135
+ credentials: ["user_key", "partner_key"],
2136
+ scopes: ["analytics:execute"],
2137
+ ownership: [{
2138
+ credential: "user_key",
2139
+ rule: "authorized_site"
2140
+ }, {
2141
+ credential: "partner_key",
2142
+ rule: "authorized_site"
2143
+ }]
2144
+ },
2145
+ request: {
2146
+ params: z.strictObject({ siteId: realtimeSchemas.publicSiteId }),
2147
+ query: null,
2148
+ headers: requestHeaders,
2149
+ body: analyticsReportDetailRequest
2150
+ },
2151
+ responses: { 200: analyticsReportDetailResponse },
2152
+ errors: analyticsRowsErrors,
2153
+ errorResponse: errorEnvelopeSchemas(analyticsRowsErrors, realtimeSchemas.publicRequestId),
2154
+ resources: {
2155
+ reads: [{
2156
+ type: "site.analytics",
2157
+ idFrom: "params.siteId"
2158
+ }],
2159
+ changes: []
2160
+ },
2161
+ lifecycle: { introduced: "1.0.0" },
2162
+ docs: {
2163
+ summary: "Query analytics report detail",
2164
+ description: "Returns the hosted analytics timeseries report with current and comparison totals.",
2165
+ tags: ["Analytics reports"],
2166
+ examples: {
2167
+ request: {
2168
+ params: { siteId: "s_01" },
2169
+ body: { state: {
2170
+ dimensions: ["date"],
2171
+ searchType: "web"
2172
+ } }
2173
+ },
2174
+ response: {
2175
+ data: {
2176
+ daily: [],
2177
+ totals: {
2178
+ clicks: 0,
2179
+ impressions: 0,
2180
+ ctr: 0,
2181
+ position: 0
2182
+ },
2183
+ meta: {
2184
+ siteUrl: "sc-domain:example.com",
2185
+ syncStatus: "synced",
2186
+ newestDateSynced: null,
2187
+ oldestDateSynced: null,
2188
+ dataDelay: "0 days"
2189
+ }
2190
+ },
2191
+ meta: {
2192
+ requestId: "req_01",
2193
+ surface: "analytics",
2194
+ version: "1.0",
2195
+ sourceName: "hosted-report",
2196
+ sourceKind: "sql",
2197
+ queryMs: 12
2198
+ }
2199
+ }
2200
+ }
2201
+ }
2202
+ })
2203
+ }
1047
2204
  });
1048
2205
  const realtime = defineHttpSurface({
1049
2206
  name: "realtime",
@@ -1199,11 +2356,35 @@ function createGscdumpV1Protocol() {
1199
2356
  requestHeaders,
1200
2357
  responseMeta,
1201
2358
  errorEnvelope,
2359
+ analyticsReportDetailRequest,
2360
+ analyticsReportDetailResponse,
2361
+ analyticsReportRequest,
2362
+ analyticsReportResponse,
1202
2363
  analyticsRowsRequest,
1203
2364
  analyticsRowsResponse,
2365
+ analysisBundleQuery,
2366
+ analysisBundleResponse,
2367
+ analysisQuery,
2368
+ analysisResponse,
2369
+ availableSitesQuery,
2370
+ availableSitesResponse,
2371
+ indexingDiagnosticsQuery,
2372
+ indexingDiagnosticsResponse,
2373
+ indexingSummaryQuery,
2374
+ indexingSummaryResponse,
2375
+ indexingUrlsQuery,
2376
+ indexingUrlsResponse,
1204
2377
  lifecycleResponse,
2378
+ registerSiteRequest,
2379
+ sitemapChangesQuery,
2380
+ sitemapChangesResponse,
2381
+ sitemapsResponse,
2382
+ siteDeletionResponse,
2383
+ siteRegistrationResponse,
1205
2384
  streamHeadResponse: headResponse,
1206
2385
  ticketResponse,
2386
+ userRegistrationResponse,
2387
+ userTokenUpdateResponse,
1207
2388
  ...realtimeSchemas
1208
2389
  },
1209
2390
  surfaces: {