gscdump 0.26.9 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.d.mts +725 -0
- package/dist/api/index.mjs +2929 -0
- package/package.json +7 -2
|
@@ -0,0 +1,2929 @@
|
|
|
1
|
+
import { ofetch } from "ofetch";
|
|
2
|
+
const MS_PER_DAY = 864e5;
|
|
3
|
+
function toIsoDate(d) {
|
|
4
|
+
return d.toISOString().slice(0, 10);
|
|
5
|
+
}
|
|
6
|
+
function addDays(dateStr, n) {
|
|
7
|
+
return toIsoDate(new Date(Date.parse(`${dateStr}T00:00:00Z`) + n * MS_PER_DAY));
|
|
8
|
+
}
|
|
9
|
+
function ok(value) {
|
|
10
|
+
return {
|
|
11
|
+
ok: true,
|
|
12
|
+
value
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function err(error) {
|
|
16
|
+
return {
|
|
17
|
+
ok: false,
|
|
18
|
+
error
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function unwrapResult(result, toError) {
|
|
22
|
+
if (result.ok) return result.value;
|
|
23
|
+
throw toError(result.error);
|
|
24
|
+
}
|
|
25
|
+
var countries_default = [
|
|
26
|
+
{
|
|
27
|
+
"name": "Afghanistan",
|
|
28
|
+
"alpha-2": "AF",
|
|
29
|
+
"alpha-3": "AFG",
|
|
30
|
+
"country-code": "004"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "Åland Islands",
|
|
34
|
+
"alpha-2": "AX",
|
|
35
|
+
"alpha-3": "ALA",
|
|
36
|
+
"country-code": "248"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "Albania",
|
|
40
|
+
"alpha-2": "AL",
|
|
41
|
+
"alpha-3": "ALB",
|
|
42
|
+
"country-code": "008"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "Algeria",
|
|
46
|
+
"alpha-2": "DZ",
|
|
47
|
+
"alpha-3": "DZA",
|
|
48
|
+
"country-code": "012"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "American Samoa",
|
|
52
|
+
"alpha-2": "AS",
|
|
53
|
+
"alpha-3": "ASM",
|
|
54
|
+
"country-code": "016"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "Andorra",
|
|
58
|
+
"alpha-2": "AD",
|
|
59
|
+
"alpha-3": "AND",
|
|
60
|
+
"country-code": "020"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "Angola",
|
|
64
|
+
"alpha-2": "AO",
|
|
65
|
+
"alpha-3": "AGO",
|
|
66
|
+
"country-code": "024"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "Anguilla",
|
|
70
|
+
"alpha-2": "AI",
|
|
71
|
+
"alpha-3": "AIA",
|
|
72
|
+
"country-code": "660"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "Antarctica",
|
|
76
|
+
"alpha-2": "AQ",
|
|
77
|
+
"alpha-3": "ATA",
|
|
78
|
+
"country-code": "010"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "Antigua and Barbuda",
|
|
82
|
+
"alpha-2": "AG",
|
|
83
|
+
"alpha-3": "ATG",
|
|
84
|
+
"country-code": "028"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "Argentina",
|
|
88
|
+
"alpha-2": "AR",
|
|
89
|
+
"alpha-3": "ARG",
|
|
90
|
+
"country-code": "032"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "Armenia",
|
|
94
|
+
"alpha-2": "AM",
|
|
95
|
+
"alpha-3": "ARM",
|
|
96
|
+
"country-code": "051"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "Aruba",
|
|
100
|
+
"alpha-2": "AW",
|
|
101
|
+
"alpha-3": "ABW",
|
|
102
|
+
"country-code": "533"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "Australia",
|
|
106
|
+
"alpha-2": "AU",
|
|
107
|
+
"alpha-3": "AUS",
|
|
108
|
+
"country-code": "036"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "Austria",
|
|
112
|
+
"alpha-2": "AT",
|
|
113
|
+
"alpha-3": "AUT",
|
|
114
|
+
"country-code": "040"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "Azerbaijan",
|
|
118
|
+
"alpha-2": "AZ",
|
|
119
|
+
"alpha-3": "AZE",
|
|
120
|
+
"country-code": "031"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "Bahamas",
|
|
124
|
+
"alpha-2": "BS",
|
|
125
|
+
"alpha-3": "BHS",
|
|
126
|
+
"country-code": "044"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "Bahrain",
|
|
130
|
+
"alpha-2": "BH",
|
|
131
|
+
"alpha-3": "BHR",
|
|
132
|
+
"country-code": "048"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"name": "Bangladesh",
|
|
136
|
+
"alpha-2": "BD",
|
|
137
|
+
"alpha-3": "BGD",
|
|
138
|
+
"country-code": "050"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "Barbados",
|
|
142
|
+
"alpha-2": "BB",
|
|
143
|
+
"alpha-3": "BRB",
|
|
144
|
+
"country-code": "052"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"name": "Belarus",
|
|
148
|
+
"alpha-2": "BY",
|
|
149
|
+
"alpha-3": "BLR",
|
|
150
|
+
"country-code": "112"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"name": "Belgium",
|
|
154
|
+
"alpha-2": "BE",
|
|
155
|
+
"alpha-3": "BEL",
|
|
156
|
+
"country-code": "056"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"name": "Belize",
|
|
160
|
+
"alpha-2": "BZ",
|
|
161
|
+
"alpha-3": "BLZ",
|
|
162
|
+
"country-code": "084"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "Benin",
|
|
166
|
+
"alpha-2": "BJ",
|
|
167
|
+
"alpha-3": "BEN",
|
|
168
|
+
"country-code": "204"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "Bermuda",
|
|
172
|
+
"alpha-2": "BM",
|
|
173
|
+
"alpha-3": "BMU",
|
|
174
|
+
"country-code": "060"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"name": "Bhutan",
|
|
178
|
+
"alpha-2": "BT",
|
|
179
|
+
"alpha-3": "BTN",
|
|
180
|
+
"country-code": "064"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "Bolivia (Plurinational State of)",
|
|
184
|
+
"alpha-2": "BO",
|
|
185
|
+
"alpha-3": "BOL",
|
|
186
|
+
"country-code": "068"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "Bonaire, Sint Eustatius and Saba",
|
|
190
|
+
"alpha-2": "BQ",
|
|
191
|
+
"alpha-3": "BES",
|
|
192
|
+
"country-code": "535"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"name": "Bosnia and Herzegovina",
|
|
196
|
+
"alpha-2": "BA",
|
|
197
|
+
"alpha-3": "BIH",
|
|
198
|
+
"country-code": "070"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"name": "Botswana",
|
|
202
|
+
"alpha-2": "BW",
|
|
203
|
+
"alpha-3": "BWA",
|
|
204
|
+
"country-code": "072"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"name": "Bouvet Island",
|
|
208
|
+
"alpha-2": "BV",
|
|
209
|
+
"alpha-3": "BVT",
|
|
210
|
+
"country-code": "074"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"name": "Brazil",
|
|
214
|
+
"alpha-2": "BR",
|
|
215
|
+
"alpha-3": "BRA",
|
|
216
|
+
"country-code": "076"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"name": "British Indian Ocean Territory",
|
|
220
|
+
"alpha-2": "IO",
|
|
221
|
+
"alpha-3": "IOT",
|
|
222
|
+
"country-code": "086"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"name": "Brunei Darussalam",
|
|
226
|
+
"alpha-2": "BN",
|
|
227
|
+
"alpha-3": "BRN",
|
|
228
|
+
"country-code": "096"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "Bulgaria",
|
|
232
|
+
"alpha-2": "BG",
|
|
233
|
+
"alpha-3": "BGR",
|
|
234
|
+
"country-code": "100"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"name": "Burkina Faso",
|
|
238
|
+
"alpha-2": "BF",
|
|
239
|
+
"alpha-3": "BFA",
|
|
240
|
+
"country-code": "854"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"name": "Burundi",
|
|
244
|
+
"alpha-2": "BI",
|
|
245
|
+
"alpha-3": "BDI",
|
|
246
|
+
"country-code": "108"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"name": "Cabo Verde",
|
|
250
|
+
"alpha-2": "CV",
|
|
251
|
+
"alpha-3": "CPV",
|
|
252
|
+
"country-code": "132"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"name": "Cambodia",
|
|
256
|
+
"alpha-2": "KH",
|
|
257
|
+
"alpha-3": "KHM",
|
|
258
|
+
"country-code": "116"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"name": "Cameroon",
|
|
262
|
+
"alpha-2": "CM",
|
|
263
|
+
"alpha-3": "CMR",
|
|
264
|
+
"country-code": "120"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"name": "Canada",
|
|
268
|
+
"alpha-2": "CA",
|
|
269
|
+
"alpha-3": "CAN",
|
|
270
|
+
"country-code": "124"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"name": "Cayman Islands",
|
|
274
|
+
"alpha-2": "KY",
|
|
275
|
+
"alpha-3": "CYM",
|
|
276
|
+
"country-code": "136"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"name": "Central African Republic",
|
|
280
|
+
"alpha-2": "CF",
|
|
281
|
+
"alpha-3": "CAF",
|
|
282
|
+
"country-code": "140"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"name": "Chad",
|
|
286
|
+
"alpha-2": "TD",
|
|
287
|
+
"alpha-3": "TCD",
|
|
288
|
+
"country-code": "148"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"name": "Chile",
|
|
292
|
+
"alpha-2": "CL",
|
|
293
|
+
"alpha-3": "CHL",
|
|
294
|
+
"country-code": "152"
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"name": "China",
|
|
298
|
+
"alpha-2": "CN",
|
|
299
|
+
"alpha-3": "CHN",
|
|
300
|
+
"country-code": "156"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"name": "Christmas Island",
|
|
304
|
+
"alpha-2": "CX",
|
|
305
|
+
"alpha-3": "CXR",
|
|
306
|
+
"country-code": "162"
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"name": "Cocos (Keeling) Islands",
|
|
310
|
+
"alpha-2": "CC",
|
|
311
|
+
"alpha-3": "CCK",
|
|
312
|
+
"country-code": "166"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"name": "Colombia",
|
|
316
|
+
"alpha-2": "CO",
|
|
317
|
+
"alpha-3": "COL",
|
|
318
|
+
"country-code": "170"
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"name": "Comoros",
|
|
322
|
+
"alpha-2": "KM",
|
|
323
|
+
"alpha-3": "COM",
|
|
324
|
+
"country-code": "174"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"name": "Congo",
|
|
328
|
+
"alpha-2": "CG",
|
|
329
|
+
"alpha-3": "COG",
|
|
330
|
+
"country-code": "178"
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"name": "Congo, Democratic Republic of the",
|
|
334
|
+
"alpha-2": "CD",
|
|
335
|
+
"alpha-3": "COD",
|
|
336
|
+
"country-code": "180"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"name": "Cook Islands",
|
|
340
|
+
"alpha-2": "CK",
|
|
341
|
+
"alpha-3": "COK",
|
|
342
|
+
"country-code": "184"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"name": "Costa Rica",
|
|
346
|
+
"alpha-2": "CR",
|
|
347
|
+
"alpha-3": "CRI",
|
|
348
|
+
"country-code": "188"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"name": "Côte d'Ivoire",
|
|
352
|
+
"alpha-2": "CI",
|
|
353
|
+
"alpha-3": "CIV",
|
|
354
|
+
"country-code": "384"
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
"name": "Croatia",
|
|
358
|
+
"alpha-2": "HR",
|
|
359
|
+
"alpha-3": "HRV",
|
|
360
|
+
"country-code": "191"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"name": "Cuba",
|
|
364
|
+
"alpha-2": "CU",
|
|
365
|
+
"alpha-3": "CUB",
|
|
366
|
+
"country-code": "192"
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"name": "Curaçao",
|
|
370
|
+
"alpha-2": "CW",
|
|
371
|
+
"alpha-3": "CUW",
|
|
372
|
+
"country-code": "531"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"name": "Cyprus",
|
|
376
|
+
"alpha-2": "CY",
|
|
377
|
+
"alpha-3": "CYP",
|
|
378
|
+
"country-code": "196"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"name": "Czechia",
|
|
382
|
+
"alpha-2": "CZ",
|
|
383
|
+
"alpha-3": "CZE",
|
|
384
|
+
"country-code": "203"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"name": "Denmark",
|
|
388
|
+
"alpha-2": "DK",
|
|
389
|
+
"alpha-3": "DNK",
|
|
390
|
+
"country-code": "208"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"name": "Djibouti",
|
|
394
|
+
"alpha-2": "DJ",
|
|
395
|
+
"alpha-3": "DJI",
|
|
396
|
+
"country-code": "262"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"name": "Dominica",
|
|
400
|
+
"alpha-2": "DM",
|
|
401
|
+
"alpha-3": "DMA",
|
|
402
|
+
"country-code": "212"
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
"name": "Dominican Republic",
|
|
406
|
+
"alpha-2": "DO",
|
|
407
|
+
"alpha-3": "DOM",
|
|
408
|
+
"country-code": "214"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"name": "Ecuador",
|
|
412
|
+
"alpha-2": "EC",
|
|
413
|
+
"alpha-3": "ECU",
|
|
414
|
+
"country-code": "218"
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"name": "Egypt",
|
|
418
|
+
"alpha-2": "EG",
|
|
419
|
+
"alpha-3": "EGY",
|
|
420
|
+
"country-code": "818"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"name": "El Salvador",
|
|
424
|
+
"alpha-2": "SV",
|
|
425
|
+
"alpha-3": "SLV",
|
|
426
|
+
"country-code": "222"
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
"name": "Equatorial Guinea",
|
|
430
|
+
"alpha-2": "GQ",
|
|
431
|
+
"alpha-3": "GNQ",
|
|
432
|
+
"country-code": "226"
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"name": "Eritrea",
|
|
436
|
+
"alpha-2": "ER",
|
|
437
|
+
"alpha-3": "ERI",
|
|
438
|
+
"country-code": "232"
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
"name": "Estonia",
|
|
442
|
+
"alpha-2": "EE",
|
|
443
|
+
"alpha-3": "EST",
|
|
444
|
+
"country-code": "233"
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"name": "Eswatini",
|
|
448
|
+
"alpha-2": "SZ",
|
|
449
|
+
"alpha-3": "SWZ",
|
|
450
|
+
"country-code": "748"
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
"name": "Ethiopia",
|
|
454
|
+
"alpha-2": "ET",
|
|
455
|
+
"alpha-3": "ETH",
|
|
456
|
+
"country-code": "231"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"name": "Falkland Islands (Malvinas)",
|
|
460
|
+
"alpha-2": "FK",
|
|
461
|
+
"alpha-3": "FLK",
|
|
462
|
+
"country-code": "238"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
"name": "Faroe Islands",
|
|
466
|
+
"alpha-2": "FO",
|
|
467
|
+
"alpha-3": "FRO",
|
|
468
|
+
"country-code": "234"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"name": "Fiji",
|
|
472
|
+
"alpha-2": "FJ",
|
|
473
|
+
"alpha-3": "FJI",
|
|
474
|
+
"country-code": "242"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"name": "Finland",
|
|
478
|
+
"alpha-2": "FI",
|
|
479
|
+
"alpha-3": "FIN",
|
|
480
|
+
"country-code": "246"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"name": "France",
|
|
484
|
+
"alpha-2": "FR",
|
|
485
|
+
"alpha-3": "FRA",
|
|
486
|
+
"country-code": "250"
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
"name": "French Guiana",
|
|
490
|
+
"alpha-2": "GF",
|
|
491
|
+
"alpha-3": "GUF",
|
|
492
|
+
"country-code": "254"
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"name": "French Polynesia",
|
|
496
|
+
"alpha-2": "PF",
|
|
497
|
+
"alpha-3": "PYF",
|
|
498
|
+
"country-code": "258"
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
"name": "French Southern Territories",
|
|
502
|
+
"alpha-2": "TF",
|
|
503
|
+
"alpha-3": "ATF",
|
|
504
|
+
"country-code": "260"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"name": "Gabon",
|
|
508
|
+
"alpha-2": "GA",
|
|
509
|
+
"alpha-3": "GAB",
|
|
510
|
+
"country-code": "266"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
"name": "Gambia",
|
|
514
|
+
"alpha-2": "GM",
|
|
515
|
+
"alpha-3": "GMB",
|
|
516
|
+
"country-code": "270"
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"name": "Georgia",
|
|
520
|
+
"alpha-2": "GE",
|
|
521
|
+
"alpha-3": "GEO",
|
|
522
|
+
"country-code": "268"
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"name": "Germany",
|
|
526
|
+
"alpha-2": "DE",
|
|
527
|
+
"alpha-3": "DEU",
|
|
528
|
+
"country-code": "276"
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
"name": "Ghana",
|
|
532
|
+
"alpha-2": "GH",
|
|
533
|
+
"alpha-3": "GHA",
|
|
534
|
+
"country-code": "288"
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
"name": "Gibraltar",
|
|
538
|
+
"alpha-2": "GI",
|
|
539
|
+
"alpha-3": "GIB",
|
|
540
|
+
"country-code": "292"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"name": "Greece",
|
|
544
|
+
"alpha-2": "GR",
|
|
545
|
+
"alpha-3": "GRC",
|
|
546
|
+
"country-code": "300"
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
"name": "Greenland",
|
|
550
|
+
"alpha-2": "GL",
|
|
551
|
+
"alpha-3": "GRL",
|
|
552
|
+
"country-code": "304"
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"name": "Grenada",
|
|
556
|
+
"alpha-2": "GD",
|
|
557
|
+
"alpha-3": "GRD",
|
|
558
|
+
"country-code": "308"
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
"name": "Guadeloupe",
|
|
562
|
+
"alpha-2": "GP",
|
|
563
|
+
"alpha-3": "GLP",
|
|
564
|
+
"country-code": "312"
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
"name": "Guam",
|
|
568
|
+
"alpha-2": "GU",
|
|
569
|
+
"alpha-3": "GUM",
|
|
570
|
+
"country-code": "316"
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
"name": "Guatemala",
|
|
574
|
+
"alpha-2": "GT",
|
|
575
|
+
"alpha-3": "GTM",
|
|
576
|
+
"country-code": "320"
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"name": "Guernsey",
|
|
580
|
+
"alpha-2": "GG",
|
|
581
|
+
"alpha-3": "GGY",
|
|
582
|
+
"country-code": "831"
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
"name": "Guinea",
|
|
586
|
+
"alpha-2": "GN",
|
|
587
|
+
"alpha-3": "GIN",
|
|
588
|
+
"country-code": "324"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"name": "Guinea-Bissau",
|
|
592
|
+
"alpha-2": "GW",
|
|
593
|
+
"alpha-3": "GNB",
|
|
594
|
+
"country-code": "624"
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
"name": "Guyana",
|
|
598
|
+
"alpha-2": "GY",
|
|
599
|
+
"alpha-3": "GUY",
|
|
600
|
+
"country-code": "328"
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"name": "Haiti",
|
|
604
|
+
"alpha-2": "HT",
|
|
605
|
+
"alpha-3": "HTI",
|
|
606
|
+
"country-code": "332"
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"name": "Heard Island and McDonald Islands",
|
|
610
|
+
"alpha-2": "HM",
|
|
611
|
+
"alpha-3": "HMD",
|
|
612
|
+
"country-code": "334"
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"name": "Holy See",
|
|
616
|
+
"alpha-2": "VA",
|
|
617
|
+
"alpha-3": "VAT",
|
|
618
|
+
"country-code": "336"
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
"name": "Honduras",
|
|
622
|
+
"alpha-2": "HN",
|
|
623
|
+
"alpha-3": "HND",
|
|
624
|
+
"country-code": "340"
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
"name": "Hong Kong",
|
|
628
|
+
"alpha-2": "HK",
|
|
629
|
+
"alpha-3": "HKG",
|
|
630
|
+
"country-code": "344"
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
"name": "Hungary",
|
|
634
|
+
"alpha-2": "HU",
|
|
635
|
+
"alpha-3": "HUN",
|
|
636
|
+
"country-code": "348"
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
"name": "Iceland",
|
|
640
|
+
"alpha-2": "IS",
|
|
641
|
+
"alpha-3": "ISL",
|
|
642
|
+
"country-code": "352"
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
"name": "India",
|
|
646
|
+
"alpha-2": "IN",
|
|
647
|
+
"alpha-3": "IND",
|
|
648
|
+
"country-code": "356"
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"name": "Indonesia",
|
|
652
|
+
"alpha-2": "ID",
|
|
653
|
+
"alpha-3": "IDN",
|
|
654
|
+
"country-code": "360"
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
"name": "Iran (Islamic Republic of)",
|
|
658
|
+
"alpha-2": "IR",
|
|
659
|
+
"alpha-3": "IRN",
|
|
660
|
+
"country-code": "364"
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
"name": "Iraq",
|
|
664
|
+
"alpha-2": "IQ",
|
|
665
|
+
"alpha-3": "IRQ",
|
|
666
|
+
"country-code": "368"
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
"name": "Ireland",
|
|
670
|
+
"alpha-2": "IE",
|
|
671
|
+
"alpha-3": "IRL",
|
|
672
|
+
"country-code": "372"
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"name": "Isle of Man",
|
|
676
|
+
"alpha-2": "IM",
|
|
677
|
+
"alpha-3": "IMN",
|
|
678
|
+
"country-code": "833"
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
"name": "Israel",
|
|
682
|
+
"alpha-2": "IL",
|
|
683
|
+
"alpha-3": "ISR",
|
|
684
|
+
"country-code": "376"
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
"name": "Italy",
|
|
688
|
+
"alpha-2": "IT",
|
|
689
|
+
"alpha-3": "ITA",
|
|
690
|
+
"country-code": "380"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
"name": "Jamaica",
|
|
694
|
+
"alpha-2": "JM",
|
|
695
|
+
"alpha-3": "JAM",
|
|
696
|
+
"country-code": "388"
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
"name": "Japan",
|
|
700
|
+
"alpha-2": "JP",
|
|
701
|
+
"alpha-3": "JPN",
|
|
702
|
+
"country-code": "392"
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
"name": "Jersey",
|
|
706
|
+
"alpha-2": "JE",
|
|
707
|
+
"alpha-3": "JEY",
|
|
708
|
+
"country-code": "832"
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
"name": "Jordan",
|
|
712
|
+
"alpha-2": "JO",
|
|
713
|
+
"alpha-3": "JOR",
|
|
714
|
+
"country-code": "400"
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
"name": "Kazakhstan",
|
|
718
|
+
"alpha-2": "KZ",
|
|
719
|
+
"alpha-3": "KAZ",
|
|
720
|
+
"country-code": "398"
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
"name": "Kenya",
|
|
724
|
+
"alpha-2": "KE",
|
|
725
|
+
"alpha-3": "KEN",
|
|
726
|
+
"country-code": "404"
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"name": "Kiribati",
|
|
730
|
+
"alpha-2": "KI",
|
|
731
|
+
"alpha-3": "KIR",
|
|
732
|
+
"country-code": "296"
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
"name": "Korea (Democratic People's Republic of)",
|
|
736
|
+
"alpha-2": "KP",
|
|
737
|
+
"alpha-3": "PRK",
|
|
738
|
+
"country-code": "408"
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
"name": "Korea, Republic of",
|
|
742
|
+
"alpha-2": "KR",
|
|
743
|
+
"alpha-3": "KOR",
|
|
744
|
+
"country-code": "410"
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
"name": "Kuwait",
|
|
748
|
+
"alpha-2": "KW",
|
|
749
|
+
"alpha-3": "KWT",
|
|
750
|
+
"country-code": "414"
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
"name": "Kyrgyzstan",
|
|
754
|
+
"alpha-2": "KG",
|
|
755
|
+
"alpha-3": "KGZ",
|
|
756
|
+
"country-code": "417"
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
"name": "Lao People's Democratic Republic",
|
|
760
|
+
"alpha-2": "LA",
|
|
761
|
+
"alpha-3": "LAO",
|
|
762
|
+
"country-code": "418"
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
"name": "Latvia",
|
|
766
|
+
"alpha-2": "LV",
|
|
767
|
+
"alpha-3": "LVA",
|
|
768
|
+
"country-code": "428"
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
"name": "Lebanon",
|
|
772
|
+
"alpha-2": "LB",
|
|
773
|
+
"alpha-3": "LBN",
|
|
774
|
+
"country-code": "422"
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
"name": "Lesotho",
|
|
778
|
+
"alpha-2": "LS",
|
|
779
|
+
"alpha-3": "LSO",
|
|
780
|
+
"country-code": "426"
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
"name": "Liberia",
|
|
784
|
+
"alpha-2": "LR",
|
|
785
|
+
"alpha-3": "LBR",
|
|
786
|
+
"country-code": "430"
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
"name": "Libya",
|
|
790
|
+
"alpha-2": "LY",
|
|
791
|
+
"alpha-3": "LBY",
|
|
792
|
+
"country-code": "434"
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
"name": "Liechtenstein",
|
|
796
|
+
"alpha-2": "LI",
|
|
797
|
+
"alpha-3": "LIE",
|
|
798
|
+
"country-code": "438"
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
"name": "Lithuania",
|
|
802
|
+
"alpha-2": "LT",
|
|
803
|
+
"alpha-3": "LTU",
|
|
804
|
+
"country-code": "440"
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
"name": "Luxembourg",
|
|
808
|
+
"alpha-2": "LU",
|
|
809
|
+
"alpha-3": "LUX",
|
|
810
|
+
"country-code": "442"
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
"name": "Macao",
|
|
814
|
+
"alpha-2": "MO",
|
|
815
|
+
"alpha-3": "MAC",
|
|
816
|
+
"country-code": "446"
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
"name": "Madagascar",
|
|
820
|
+
"alpha-2": "MG",
|
|
821
|
+
"alpha-3": "MDG",
|
|
822
|
+
"country-code": "450"
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
"name": "Malawi",
|
|
826
|
+
"alpha-2": "MW",
|
|
827
|
+
"alpha-3": "MWI",
|
|
828
|
+
"country-code": "454"
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
"name": "Malaysia",
|
|
832
|
+
"alpha-2": "MY",
|
|
833
|
+
"alpha-3": "MYS",
|
|
834
|
+
"country-code": "458"
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
"name": "Maldives",
|
|
838
|
+
"alpha-2": "MV",
|
|
839
|
+
"alpha-3": "MDV",
|
|
840
|
+
"country-code": "462"
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
"name": "Mali",
|
|
844
|
+
"alpha-2": "ML",
|
|
845
|
+
"alpha-3": "MLI",
|
|
846
|
+
"country-code": "466"
|
|
847
|
+
},
|
|
848
|
+
{
|
|
849
|
+
"name": "Malta",
|
|
850
|
+
"alpha-2": "MT",
|
|
851
|
+
"alpha-3": "MLT",
|
|
852
|
+
"country-code": "470"
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
"name": "Marshall Islands",
|
|
856
|
+
"alpha-2": "MH",
|
|
857
|
+
"alpha-3": "MHL",
|
|
858
|
+
"country-code": "584"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
"name": "Martinique",
|
|
862
|
+
"alpha-2": "MQ",
|
|
863
|
+
"alpha-3": "MTQ",
|
|
864
|
+
"country-code": "474"
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
"name": "Mauritania",
|
|
868
|
+
"alpha-2": "MR",
|
|
869
|
+
"alpha-3": "MRT",
|
|
870
|
+
"country-code": "478"
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
"name": "Mauritius",
|
|
874
|
+
"alpha-2": "MU",
|
|
875
|
+
"alpha-3": "MUS",
|
|
876
|
+
"country-code": "480"
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
"name": "Mayotte",
|
|
880
|
+
"alpha-2": "YT",
|
|
881
|
+
"alpha-3": "MYT",
|
|
882
|
+
"country-code": "175"
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
"name": "Mexico",
|
|
886
|
+
"alpha-2": "MX",
|
|
887
|
+
"alpha-3": "MEX",
|
|
888
|
+
"country-code": "484"
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
"name": "Micronesia (Federated States of)",
|
|
892
|
+
"alpha-2": "FM",
|
|
893
|
+
"alpha-3": "FSM",
|
|
894
|
+
"country-code": "583"
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
"name": "Moldova, Republic of",
|
|
898
|
+
"alpha-2": "MD",
|
|
899
|
+
"alpha-3": "MDA",
|
|
900
|
+
"country-code": "498"
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
"name": "Monaco",
|
|
904
|
+
"alpha-2": "MC",
|
|
905
|
+
"alpha-3": "MCO",
|
|
906
|
+
"country-code": "492"
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
"name": "Mongolia",
|
|
910
|
+
"alpha-2": "MN",
|
|
911
|
+
"alpha-3": "MNG",
|
|
912
|
+
"country-code": "496"
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
"name": "Montenegro",
|
|
916
|
+
"alpha-2": "ME",
|
|
917
|
+
"alpha-3": "MNE",
|
|
918
|
+
"country-code": "499"
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
"name": "Montserrat",
|
|
922
|
+
"alpha-2": "MS",
|
|
923
|
+
"alpha-3": "MSR",
|
|
924
|
+
"country-code": "500"
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
"name": "Morocco",
|
|
928
|
+
"alpha-2": "MA",
|
|
929
|
+
"alpha-3": "MAR",
|
|
930
|
+
"country-code": "504"
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
"name": "Mozambique",
|
|
934
|
+
"alpha-2": "MZ",
|
|
935
|
+
"alpha-3": "MOZ",
|
|
936
|
+
"country-code": "508"
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
"name": "Myanmar",
|
|
940
|
+
"alpha-2": "MM",
|
|
941
|
+
"alpha-3": "MMR",
|
|
942
|
+
"country-code": "104"
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
"name": "Namibia",
|
|
946
|
+
"alpha-2": "NA",
|
|
947
|
+
"alpha-3": "NAM",
|
|
948
|
+
"country-code": "516"
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
"name": "Nauru",
|
|
952
|
+
"alpha-2": "NR",
|
|
953
|
+
"alpha-3": "NRU",
|
|
954
|
+
"country-code": "520"
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
"name": "Nepal",
|
|
958
|
+
"alpha-2": "NP",
|
|
959
|
+
"alpha-3": "NPL",
|
|
960
|
+
"country-code": "524"
|
|
961
|
+
},
|
|
962
|
+
{
|
|
963
|
+
"name": "Netherlands",
|
|
964
|
+
"alpha-2": "NL",
|
|
965
|
+
"alpha-3": "NLD",
|
|
966
|
+
"country-code": "528"
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
"name": "New Caledonia",
|
|
970
|
+
"alpha-2": "NC",
|
|
971
|
+
"alpha-3": "NCL",
|
|
972
|
+
"country-code": "540"
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
"name": "New Zealand",
|
|
976
|
+
"alpha-2": "NZ",
|
|
977
|
+
"alpha-3": "NZL",
|
|
978
|
+
"country-code": "554"
|
|
979
|
+
},
|
|
980
|
+
{
|
|
981
|
+
"name": "Nicaragua",
|
|
982
|
+
"alpha-2": "NI",
|
|
983
|
+
"alpha-3": "NIC",
|
|
984
|
+
"country-code": "558"
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
"name": "Niger",
|
|
988
|
+
"alpha-2": "NE",
|
|
989
|
+
"alpha-3": "NER",
|
|
990
|
+
"country-code": "562"
|
|
991
|
+
},
|
|
992
|
+
{
|
|
993
|
+
"name": "Nigeria",
|
|
994
|
+
"alpha-2": "NG",
|
|
995
|
+
"alpha-3": "NGA",
|
|
996
|
+
"country-code": "566"
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
"name": "Niue",
|
|
1000
|
+
"alpha-2": "NU",
|
|
1001
|
+
"alpha-3": "NIU",
|
|
1002
|
+
"country-code": "570"
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
"name": "Norfolk Island",
|
|
1006
|
+
"alpha-2": "NF",
|
|
1007
|
+
"alpha-3": "NFK",
|
|
1008
|
+
"country-code": "574"
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
"name": "North Macedonia",
|
|
1012
|
+
"alpha-2": "MK",
|
|
1013
|
+
"alpha-3": "MKD",
|
|
1014
|
+
"country-code": "807"
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
"name": "Northern Mariana Islands",
|
|
1018
|
+
"alpha-2": "MP",
|
|
1019
|
+
"alpha-3": "MNP",
|
|
1020
|
+
"country-code": "580"
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
"name": "Norway",
|
|
1024
|
+
"alpha-2": "NO",
|
|
1025
|
+
"alpha-3": "NOR",
|
|
1026
|
+
"country-code": "578"
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
"name": "Oman",
|
|
1030
|
+
"alpha-2": "OM",
|
|
1031
|
+
"alpha-3": "OMN",
|
|
1032
|
+
"country-code": "512"
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
"name": "Pakistan",
|
|
1036
|
+
"alpha-2": "PK",
|
|
1037
|
+
"alpha-3": "PAK",
|
|
1038
|
+
"country-code": "586"
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
"name": "Palau",
|
|
1042
|
+
"alpha-2": "PW",
|
|
1043
|
+
"alpha-3": "PLW",
|
|
1044
|
+
"country-code": "585"
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
"name": "Palestine, State of",
|
|
1048
|
+
"alpha-2": "PS",
|
|
1049
|
+
"alpha-3": "PSE",
|
|
1050
|
+
"country-code": "275"
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
"name": "Panama",
|
|
1054
|
+
"alpha-2": "PA",
|
|
1055
|
+
"alpha-3": "PAN",
|
|
1056
|
+
"country-code": "591"
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
"name": "Papua New Guinea",
|
|
1060
|
+
"alpha-2": "PG",
|
|
1061
|
+
"alpha-3": "PNG",
|
|
1062
|
+
"country-code": "598"
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
"name": "Paraguay",
|
|
1066
|
+
"alpha-2": "PY",
|
|
1067
|
+
"alpha-3": "PRY",
|
|
1068
|
+
"country-code": "600"
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
"name": "Peru",
|
|
1072
|
+
"alpha-2": "PE",
|
|
1073
|
+
"alpha-3": "PER",
|
|
1074
|
+
"country-code": "604"
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
"name": "Philippines",
|
|
1078
|
+
"alpha-2": "PH",
|
|
1079
|
+
"alpha-3": "PHL",
|
|
1080
|
+
"country-code": "608"
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
"name": "Pitcairn",
|
|
1084
|
+
"alpha-2": "PN",
|
|
1085
|
+
"alpha-3": "PCN",
|
|
1086
|
+
"country-code": "612"
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
"name": "Poland",
|
|
1090
|
+
"alpha-2": "PL",
|
|
1091
|
+
"alpha-3": "POL",
|
|
1092
|
+
"country-code": "616"
|
|
1093
|
+
},
|
|
1094
|
+
{
|
|
1095
|
+
"name": "Portugal",
|
|
1096
|
+
"alpha-2": "PT",
|
|
1097
|
+
"alpha-3": "PRT",
|
|
1098
|
+
"country-code": "620"
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
"name": "Puerto Rico",
|
|
1102
|
+
"alpha-2": "PR",
|
|
1103
|
+
"alpha-3": "PRI",
|
|
1104
|
+
"country-code": "630"
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
"name": "Qatar",
|
|
1108
|
+
"alpha-2": "QA",
|
|
1109
|
+
"alpha-3": "QAT",
|
|
1110
|
+
"country-code": "634"
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
"name": "Réunion",
|
|
1114
|
+
"alpha-2": "RE",
|
|
1115
|
+
"alpha-3": "REU",
|
|
1116
|
+
"country-code": "638"
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
"name": "Romania",
|
|
1120
|
+
"alpha-2": "RO",
|
|
1121
|
+
"alpha-3": "ROU",
|
|
1122
|
+
"country-code": "642"
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
"name": "Russian Federation",
|
|
1126
|
+
"alpha-2": "RU",
|
|
1127
|
+
"alpha-3": "RUS",
|
|
1128
|
+
"country-code": "643"
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
"name": "Rwanda",
|
|
1132
|
+
"alpha-2": "RW",
|
|
1133
|
+
"alpha-3": "RWA",
|
|
1134
|
+
"country-code": "646"
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
"name": "Saint Barthélemy",
|
|
1138
|
+
"alpha-2": "BL",
|
|
1139
|
+
"alpha-3": "BLM",
|
|
1140
|
+
"country-code": "652"
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
"name": "Saint Helena, Ascension and Tristan da Cunha",
|
|
1144
|
+
"alpha-2": "SH",
|
|
1145
|
+
"alpha-3": "SHN",
|
|
1146
|
+
"country-code": "654"
|
|
1147
|
+
},
|
|
1148
|
+
{
|
|
1149
|
+
"name": "Saint Kitts and Nevis",
|
|
1150
|
+
"alpha-2": "KN",
|
|
1151
|
+
"alpha-3": "KNA",
|
|
1152
|
+
"country-code": "659"
|
|
1153
|
+
},
|
|
1154
|
+
{
|
|
1155
|
+
"name": "Saint Lucia",
|
|
1156
|
+
"alpha-2": "LC",
|
|
1157
|
+
"alpha-3": "LCA",
|
|
1158
|
+
"country-code": "662"
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
"name": "Saint Martin (French part)",
|
|
1162
|
+
"alpha-2": "MF",
|
|
1163
|
+
"alpha-3": "MAF",
|
|
1164
|
+
"country-code": "663"
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
"name": "Saint Pierre and Miquelon",
|
|
1168
|
+
"alpha-2": "PM",
|
|
1169
|
+
"alpha-3": "SPM",
|
|
1170
|
+
"country-code": "666"
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
"name": "Saint Vincent and the Grenadines",
|
|
1174
|
+
"alpha-2": "VC",
|
|
1175
|
+
"alpha-3": "VCT",
|
|
1176
|
+
"country-code": "670"
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
"name": "Samoa",
|
|
1180
|
+
"alpha-2": "WS",
|
|
1181
|
+
"alpha-3": "WSM",
|
|
1182
|
+
"country-code": "882"
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
"name": "San Marino",
|
|
1186
|
+
"alpha-2": "SM",
|
|
1187
|
+
"alpha-3": "SMR",
|
|
1188
|
+
"country-code": "674"
|
|
1189
|
+
},
|
|
1190
|
+
{
|
|
1191
|
+
"name": "Sao Tome and Principe",
|
|
1192
|
+
"alpha-2": "ST",
|
|
1193
|
+
"alpha-3": "STP",
|
|
1194
|
+
"country-code": "678"
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
"name": "Saudi Arabia",
|
|
1198
|
+
"alpha-2": "SA",
|
|
1199
|
+
"alpha-3": "SAU",
|
|
1200
|
+
"country-code": "682"
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
"name": "Senegal",
|
|
1204
|
+
"alpha-2": "SN",
|
|
1205
|
+
"alpha-3": "SEN",
|
|
1206
|
+
"country-code": "686"
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
"name": "Serbia",
|
|
1210
|
+
"alpha-2": "RS",
|
|
1211
|
+
"alpha-3": "SRB",
|
|
1212
|
+
"country-code": "688"
|
|
1213
|
+
},
|
|
1214
|
+
{
|
|
1215
|
+
"name": "Seychelles",
|
|
1216
|
+
"alpha-2": "SC",
|
|
1217
|
+
"alpha-3": "SYC",
|
|
1218
|
+
"country-code": "690"
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
"name": "Sierra Leone",
|
|
1222
|
+
"alpha-2": "SL",
|
|
1223
|
+
"alpha-3": "SLE",
|
|
1224
|
+
"country-code": "694"
|
|
1225
|
+
},
|
|
1226
|
+
{
|
|
1227
|
+
"name": "Singapore",
|
|
1228
|
+
"alpha-2": "SG",
|
|
1229
|
+
"alpha-3": "SGP",
|
|
1230
|
+
"country-code": "702"
|
|
1231
|
+
},
|
|
1232
|
+
{
|
|
1233
|
+
"name": "Sint Maarten (Dutch part)",
|
|
1234
|
+
"alpha-2": "SX",
|
|
1235
|
+
"alpha-3": "SXM",
|
|
1236
|
+
"country-code": "534"
|
|
1237
|
+
},
|
|
1238
|
+
{
|
|
1239
|
+
"name": "Slovakia",
|
|
1240
|
+
"alpha-2": "SK",
|
|
1241
|
+
"alpha-3": "SVK",
|
|
1242
|
+
"country-code": "703"
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
"name": "Slovenia",
|
|
1246
|
+
"alpha-2": "SI",
|
|
1247
|
+
"alpha-3": "SVN",
|
|
1248
|
+
"country-code": "705"
|
|
1249
|
+
},
|
|
1250
|
+
{
|
|
1251
|
+
"name": "Solomon Islands",
|
|
1252
|
+
"alpha-2": "SB",
|
|
1253
|
+
"alpha-3": "SLB",
|
|
1254
|
+
"country-code": "090"
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
"name": "Somalia",
|
|
1258
|
+
"alpha-2": "SO",
|
|
1259
|
+
"alpha-3": "SOM",
|
|
1260
|
+
"country-code": "706"
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
"name": "South Africa",
|
|
1264
|
+
"alpha-2": "ZA",
|
|
1265
|
+
"alpha-3": "ZAF",
|
|
1266
|
+
"country-code": "710"
|
|
1267
|
+
},
|
|
1268
|
+
{
|
|
1269
|
+
"name": "South Georgia and the South Sandwich Islands",
|
|
1270
|
+
"alpha-2": "GS",
|
|
1271
|
+
"alpha-3": "SGS",
|
|
1272
|
+
"country-code": "239"
|
|
1273
|
+
},
|
|
1274
|
+
{
|
|
1275
|
+
"name": "South Sudan",
|
|
1276
|
+
"alpha-2": "SS",
|
|
1277
|
+
"alpha-3": "SSD",
|
|
1278
|
+
"country-code": "728"
|
|
1279
|
+
},
|
|
1280
|
+
{
|
|
1281
|
+
"name": "Spain",
|
|
1282
|
+
"alpha-2": "ES",
|
|
1283
|
+
"alpha-3": "ESP",
|
|
1284
|
+
"country-code": "724"
|
|
1285
|
+
},
|
|
1286
|
+
{
|
|
1287
|
+
"name": "Sri Lanka",
|
|
1288
|
+
"alpha-2": "LK",
|
|
1289
|
+
"alpha-3": "LKA",
|
|
1290
|
+
"country-code": "144"
|
|
1291
|
+
},
|
|
1292
|
+
{
|
|
1293
|
+
"name": "Sudan",
|
|
1294
|
+
"alpha-2": "SD",
|
|
1295
|
+
"alpha-3": "SDN",
|
|
1296
|
+
"country-code": "729"
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
"name": "Suriname",
|
|
1300
|
+
"alpha-2": "SR",
|
|
1301
|
+
"alpha-3": "SUR",
|
|
1302
|
+
"country-code": "740"
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
"name": "Svalbard and Jan Mayen",
|
|
1306
|
+
"alpha-2": "SJ",
|
|
1307
|
+
"alpha-3": "SJM",
|
|
1308
|
+
"country-code": "744"
|
|
1309
|
+
},
|
|
1310
|
+
{
|
|
1311
|
+
"name": "Sweden",
|
|
1312
|
+
"alpha-2": "SE",
|
|
1313
|
+
"alpha-3": "SWE",
|
|
1314
|
+
"country-code": "752"
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
"name": "Switzerland",
|
|
1318
|
+
"alpha-2": "CH",
|
|
1319
|
+
"alpha-3": "CHE",
|
|
1320
|
+
"country-code": "756"
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
"name": "Syrian Arab Republic",
|
|
1324
|
+
"alpha-2": "SY",
|
|
1325
|
+
"alpha-3": "SYR",
|
|
1326
|
+
"country-code": "760"
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
"name": "Taiwan",
|
|
1330
|
+
"alpha-2": "TW",
|
|
1331
|
+
"alpha-3": "TWN",
|
|
1332
|
+
"country-code": "158"
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
"name": "Tajikistan",
|
|
1336
|
+
"alpha-2": "TJ",
|
|
1337
|
+
"alpha-3": "TJK",
|
|
1338
|
+
"country-code": "762"
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
"name": "Tanzania, United Republic of",
|
|
1342
|
+
"alpha-2": "TZ",
|
|
1343
|
+
"alpha-3": "TZA",
|
|
1344
|
+
"country-code": "834"
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
"name": "Thailand",
|
|
1348
|
+
"alpha-2": "TH",
|
|
1349
|
+
"alpha-3": "THA",
|
|
1350
|
+
"country-code": "764"
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
"name": "Timor-Leste",
|
|
1354
|
+
"alpha-2": "TL",
|
|
1355
|
+
"alpha-3": "TLS",
|
|
1356
|
+
"country-code": "626"
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
"name": "Togo",
|
|
1360
|
+
"alpha-2": "TG",
|
|
1361
|
+
"alpha-3": "TGO",
|
|
1362
|
+
"country-code": "768"
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
"name": "Tokelau",
|
|
1366
|
+
"alpha-2": "TK",
|
|
1367
|
+
"alpha-3": "TKL",
|
|
1368
|
+
"country-code": "772"
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
"name": "Tonga",
|
|
1372
|
+
"alpha-2": "TO",
|
|
1373
|
+
"alpha-3": "TON",
|
|
1374
|
+
"country-code": "776"
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
"name": "Trinidad and Tobago",
|
|
1378
|
+
"alpha-2": "TT",
|
|
1379
|
+
"alpha-3": "TTO",
|
|
1380
|
+
"country-code": "780"
|
|
1381
|
+
},
|
|
1382
|
+
{
|
|
1383
|
+
"name": "Tunisia",
|
|
1384
|
+
"alpha-2": "TN",
|
|
1385
|
+
"alpha-3": "TUN",
|
|
1386
|
+
"country-code": "788"
|
|
1387
|
+
},
|
|
1388
|
+
{
|
|
1389
|
+
"name": "Turkey",
|
|
1390
|
+
"alpha-2": "TR",
|
|
1391
|
+
"alpha-3": "TUR",
|
|
1392
|
+
"country-code": "792"
|
|
1393
|
+
},
|
|
1394
|
+
{
|
|
1395
|
+
"name": "Turkmenistan",
|
|
1396
|
+
"alpha-2": "TM",
|
|
1397
|
+
"alpha-3": "TKM",
|
|
1398
|
+
"country-code": "795"
|
|
1399
|
+
},
|
|
1400
|
+
{
|
|
1401
|
+
"name": "Turks and Caicos Islands",
|
|
1402
|
+
"alpha-2": "TC",
|
|
1403
|
+
"alpha-3": "TCA",
|
|
1404
|
+
"country-code": "796"
|
|
1405
|
+
},
|
|
1406
|
+
{
|
|
1407
|
+
"name": "Tuvalu",
|
|
1408
|
+
"alpha-2": "TV",
|
|
1409
|
+
"alpha-3": "TUV",
|
|
1410
|
+
"country-code": "798"
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
"name": "Uganda",
|
|
1414
|
+
"alpha-2": "UG",
|
|
1415
|
+
"alpha-3": "UGA",
|
|
1416
|
+
"country-code": "800"
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
"name": "Ukraine",
|
|
1420
|
+
"alpha-2": "UA",
|
|
1421
|
+
"alpha-3": "UKR",
|
|
1422
|
+
"country-code": "804"
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
"name": "United Arab Emirates",
|
|
1426
|
+
"alpha-2": "AE",
|
|
1427
|
+
"alpha-3": "ARE",
|
|
1428
|
+
"country-code": "784"
|
|
1429
|
+
},
|
|
1430
|
+
{
|
|
1431
|
+
"name": "United Kingdom",
|
|
1432
|
+
"alpha-2": "GB",
|
|
1433
|
+
"alpha-3": "GBR",
|
|
1434
|
+
"country-code": "826"
|
|
1435
|
+
},
|
|
1436
|
+
{
|
|
1437
|
+
"name": "America",
|
|
1438
|
+
"alpha-2": "US",
|
|
1439
|
+
"alpha-3": "USA",
|
|
1440
|
+
"country-code": "840"
|
|
1441
|
+
},
|
|
1442
|
+
{
|
|
1443
|
+
"name": "United States Minor Outlying Islands",
|
|
1444
|
+
"alpha-2": "UM",
|
|
1445
|
+
"alpha-3": "UMI",
|
|
1446
|
+
"country-code": "581"
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
"name": "Uruguay",
|
|
1450
|
+
"alpha-2": "UY",
|
|
1451
|
+
"alpha-3": "URY",
|
|
1452
|
+
"country-code": "858"
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
"name": "Uzbekistan",
|
|
1456
|
+
"alpha-2": "UZ",
|
|
1457
|
+
"alpha-3": "UZB",
|
|
1458
|
+
"country-code": "860"
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
"name": "Vanuatu",
|
|
1462
|
+
"alpha-2": "VU",
|
|
1463
|
+
"alpha-3": "VUT",
|
|
1464
|
+
"country-code": "548"
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
"name": "Venezuela (Bolivarian Republic of)",
|
|
1468
|
+
"alpha-2": "VE",
|
|
1469
|
+
"alpha-3": "VEN",
|
|
1470
|
+
"country-code": "862"
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
"name": "Vietnam",
|
|
1474
|
+
"alpha-2": "VN",
|
|
1475
|
+
"alpha-3": "VNM",
|
|
1476
|
+
"country-code": "704"
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
"name": "Virgin Islands (British)",
|
|
1480
|
+
"alpha-2": "VG",
|
|
1481
|
+
"alpha-3": "VGB",
|
|
1482
|
+
"country-code": "092"
|
|
1483
|
+
},
|
|
1484
|
+
{
|
|
1485
|
+
"name": "Virgin Islands (U.S.)",
|
|
1486
|
+
"alpha-2": "VI",
|
|
1487
|
+
"alpha-3": "VIR",
|
|
1488
|
+
"country-code": "850"
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
"name": "Wallis and Futuna",
|
|
1492
|
+
"alpha-2": "WF",
|
|
1493
|
+
"alpha-3": "WLF",
|
|
1494
|
+
"country-code": "876"
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
"name": "Western Sahara",
|
|
1498
|
+
"alpha-2": "EH",
|
|
1499
|
+
"alpha-3": "ESH",
|
|
1500
|
+
"country-code": "732"
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
"name": "Yemen",
|
|
1504
|
+
"alpha-2": "YE",
|
|
1505
|
+
"alpha-3": "YEM",
|
|
1506
|
+
"country-code": "887"
|
|
1507
|
+
},
|
|
1508
|
+
{
|
|
1509
|
+
"name": "Zambia",
|
|
1510
|
+
"alpha-2": "ZM",
|
|
1511
|
+
"alpha-3": "ZMB",
|
|
1512
|
+
"country-code": "894"
|
|
1513
|
+
},
|
|
1514
|
+
{
|
|
1515
|
+
"name": "Zimbabwe",
|
|
1516
|
+
"alpha-2": "ZW",
|
|
1517
|
+
"alpha-3": "ZWE",
|
|
1518
|
+
"country-code": "716"
|
|
1519
|
+
}
|
|
1520
|
+
];
|
|
1521
|
+
const SearchTypes = {
|
|
1522
|
+
WEB: "web",
|
|
1523
|
+
IMAGE: "image",
|
|
1524
|
+
VIDEO: "video",
|
|
1525
|
+
NEWS: "news",
|
|
1526
|
+
DISCOVER: "discover",
|
|
1527
|
+
GOOGLE_NEWS: "googleNews"
|
|
1528
|
+
};
|
|
1529
|
+
Object.fromEntries(countries_default.map((c) => [c["alpha-3"], c["alpha-3"].toLowerCase()]));
|
|
1530
|
+
const TIME_AXIS_DIMENSIONS = new Set(["date", "hour"]);
|
|
1531
|
+
const queryErrors = {
|
|
1532
|
+
missingDateRange() {
|
|
1533
|
+
return {
|
|
1534
|
+
kind: "missing-date-range",
|
|
1535
|
+
message: "Date range required: use .where(between(date, start, end)) or .where(and(gte(date, start), lte(date, end)))"
|
|
1536
|
+
};
|
|
1537
|
+
},
|
|
1538
|
+
invalidRowLimit(value) {
|
|
1539
|
+
return {
|
|
1540
|
+
kind: "invalid-row-limit",
|
|
1541
|
+
value,
|
|
1542
|
+
message: `rowLimit must be a positive integer, got ${value}`
|
|
1543
|
+
};
|
|
1544
|
+
},
|
|
1545
|
+
invalidStartRow(value) {
|
|
1546
|
+
return {
|
|
1547
|
+
kind: "invalid-start-row",
|
|
1548
|
+
value,
|
|
1549
|
+
message: `startRow must be a non-negative integer, got ${value}`
|
|
1550
|
+
};
|
|
1551
|
+
},
|
|
1552
|
+
hourDimensionRequiresHourlyState() {
|
|
1553
|
+
return {
|
|
1554
|
+
kind: "invalid-data-state",
|
|
1555
|
+
message: "hour dimension requires dataState: \"hourly_all\""
|
|
1556
|
+
};
|
|
1557
|
+
},
|
|
1558
|
+
hourlyStateRequiresHourDimension() {
|
|
1559
|
+
return {
|
|
1560
|
+
kind: "invalid-data-state",
|
|
1561
|
+
message: "dataState: \"hourly_all\" requires grouping by hour dimension"
|
|
1562
|
+
};
|
|
1563
|
+
},
|
|
1564
|
+
byPropertyUnsupportedSearchType() {
|
|
1565
|
+
return {
|
|
1566
|
+
kind: "invalid-aggregation-type",
|
|
1567
|
+
message: "aggregationType: \"byProperty\" is not supported for type \"discover\" or \"googleNews\""
|
|
1568
|
+
};
|
|
1569
|
+
},
|
|
1570
|
+
byPropertyNotAllowedWithPage() {
|
|
1571
|
+
return {
|
|
1572
|
+
kind: "invalid-aggregation-type",
|
|
1573
|
+
message: "aggregationType: \"byProperty\" is not allowed when grouping or filtering by page"
|
|
1574
|
+
};
|
|
1575
|
+
},
|
|
1576
|
+
byNewsShowcaseRequiresSearchType() {
|
|
1577
|
+
return {
|
|
1578
|
+
kind: "invalid-aggregation-type",
|
|
1579
|
+
message: "aggregationType: \"byNewsShowcasePanel\" requires type \"discover\" or \"googleNews\""
|
|
1580
|
+
};
|
|
1581
|
+
},
|
|
1582
|
+
byNewsShowcaseNotAllowedWithPage() {
|
|
1583
|
+
return {
|
|
1584
|
+
kind: "invalid-aggregation-type",
|
|
1585
|
+
message: "aggregationType: \"byNewsShowcasePanel\" is not allowed when grouping or filtering by page"
|
|
1586
|
+
};
|
|
1587
|
+
},
|
|
1588
|
+
byNewsShowcaseRequiresShowcaseFilter() {
|
|
1589
|
+
return {
|
|
1590
|
+
kind: "invalid-aggregation-type",
|
|
1591
|
+
message: "aggregationType: \"byNewsShowcasePanel\" requires a searchAppearance equals \"NEWS_SHOWCASE\" filter and no other searchAppearance filter"
|
|
1592
|
+
};
|
|
1593
|
+
},
|
|
1594
|
+
invalidBuilderState(cause) {
|
|
1595
|
+
return {
|
|
1596
|
+
kind: "invalid-builder-state",
|
|
1597
|
+
cause,
|
|
1598
|
+
message: "Invalid state"
|
|
1599
|
+
};
|
|
1600
|
+
},
|
|
1601
|
+
unsupportedCapability(capability, context) {
|
|
1602
|
+
return {
|
|
1603
|
+
kind: "unsupported-capability",
|
|
1604
|
+
capability,
|
|
1605
|
+
context,
|
|
1606
|
+
message: `${context} requires ${capability} capability`
|
|
1607
|
+
};
|
|
1608
|
+
},
|
|
1609
|
+
unresolvableDataset(dimensions, filterDims = []) {
|
|
1610
|
+
const grouped = dimensions.filter((d) => !TIME_AXIS_DIMENSIONS.has(d));
|
|
1611
|
+
const filtered = filterDims.filter((d) => !TIME_AXIS_DIMENSIONS.has(d));
|
|
1612
|
+
return {
|
|
1613
|
+
kind: "unresolvable-dataset",
|
|
1614
|
+
dimensions,
|
|
1615
|
+
filterDims,
|
|
1616
|
+
message: `Cannot resolve a [${grouped.join(", ")}] breakdown filtered by [${filtered.join(", ")}] from stored data: these dimensions live in separate per-dimension tables. Only the live GSC API computes cross-dimension aggregates.`
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
var UnsupportedLogicalCapabilityError = class extends Error {
|
|
1621
|
+
queryError;
|
|
1622
|
+
constructor(capability, context) {
|
|
1623
|
+
const error = queryErrors.unsupportedCapability(capability, context);
|
|
1624
|
+
super(error.message);
|
|
1625
|
+
this.name = "UnsupportedLogicalCapabilityError";
|
|
1626
|
+
this.queryError = error;
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
var UnresolvableDatasetError = class extends Error {
|
|
1630
|
+
queryError;
|
|
1631
|
+
constructor(dimensions, filterDims = []) {
|
|
1632
|
+
const error = queryErrors.unresolvableDataset(dimensions, filterDims);
|
|
1633
|
+
super(error.message);
|
|
1634
|
+
this.name = "UnresolvableDatasetError";
|
|
1635
|
+
this.queryError = error;
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
function queryErrorToException(error) {
|
|
1639
|
+
switch (error.kind) {
|
|
1640
|
+
case "unsupported-capability": return new UnsupportedLogicalCapabilityError(error.capability, error.context);
|
|
1641
|
+
case "unresolvable-dataset": return new UnresolvableDatasetError(error.dimensions, error.filterDims);
|
|
1642
|
+
default: {
|
|
1643
|
+
const exception = new Error(error.message);
|
|
1644
|
+
if ("cause" in error && error.cause !== void 0) exception.cause = error.cause;
|
|
1645
|
+
exception.queryError = error;
|
|
1646
|
+
return exception;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
const DATE_OPERATORS = [
|
|
1651
|
+
"gte",
|
|
1652
|
+
"gt",
|
|
1653
|
+
"lte",
|
|
1654
|
+
"lt",
|
|
1655
|
+
"between"
|
|
1656
|
+
];
|
|
1657
|
+
const METRIC_OPERATORS = [
|
|
1658
|
+
"metricGte",
|
|
1659
|
+
"metricGt",
|
|
1660
|
+
"metricLte",
|
|
1661
|
+
"metricLt",
|
|
1662
|
+
"metricBetween"
|
|
1663
|
+
];
|
|
1664
|
+
const SPECIAL_OPERATORS = ["topLevel"];
|
|
1665
|
+
const QUERY_PARAMS = ["searchType"];
|
|
1666
|
+
function isDateOperator(op) {
|
|
1667
|
+
return DATE_OPERATORS.includes(op);
|
|
1668
|
+
}
|
|
1669
|
+
function isMetricOperator(op) {
|
|
1670
|
+
return METRIC_OPERATORS.includes(op);
|
|
1671
|
+
}
|
|
1672
|
+
function isSpecialOperator(op) {
|
|
1673
|
+
return SPECIAL_OPERATORS.includes(op);
|
|
1674
|
+
}
|
|
1675
|
+
function isQueryParam(value) {
|
|
1676
|
+
return QUERY_PARAMS.includes(value);
|
|
1677
|
+
}
|
|
1678
|
+
new Set(Object.values(SearchTypes));
|
|
1679
|
+
function extractSpecialFilters(filter) {
|
|
1680
|
+
if (!filter) return {};
|
|
1681
|
+
let startDate;
|
|
1682
|
+
let endDate;
|
|
1683
|
+
let searchType;
|
|
1684
|
+
const otherFilters = [];
|
|
1685
|
+
const cleanedNestedGroups = [];
|
|
1686
|
+
for (const f of filter._filters) if (f.dimension === "date" && isDateOperator(f.operator)) switch (f.operator) {
|
|
1687
|
+
case "gte":
|
|
1688
|
+
startDate = f.expression;
|
|
1689
|
+
break;
|
|
1690
|
+
case "gt":
|
|
1691
|
+
startDate = addDays(f.expression, 1);
|
|
1692
|
+
break;
|
|
1693
|
+
case "lte":
|
|
1694
|
+
endDate = f.expression;
|
|
1695
|
+
break;
|
|
1696
|
+
case "lt":
|
|
1697
|
+
endDate = addDays(f.expression, -1);
|
|
1698
|
+
break;
|
|
1699
|
+
case "between":
|
|
1700
|
+
startDate = f.expression;
|
|
1701
|
+
endDate = f.expression2;
|
|
1702
|
+
break;
|
|
1703
|
+
}
|
|
1704
|
+
else if (isQueryParam(f.dimension)) {
|
|
1705
|
+
if (f.dimension === "searchType") searchType = f.expression;
|
|
1706
|
+
} else if (isMetricOperator(f.operator) || isSpecialOperator(f.operator)) otherFilters.push(f);
|
|
1707
|
+
else otherFilters.push(f);
|
|
1708
|
+
if (filter._nestedGroups) for (const nested of filter._nestedGroups) {
|
|
1709
|
+
const extracted = extractSpecialFilters(nested);
|
|
1710
|
+
if (!startDate && extracted.startDate) startDate = extracted.startDate;
|
|
1711
|
+
if (!endDate && extracted.endDate) endDate = extracted.endDate;
|
|
1712
|
+
if (!searchType && extracted.searchType) searchType = extracted.searchType;
|
|
1713
|
+
if (extracted.dimensionFilter) cleanedNestedGroups.push(extracted.dimensionFilter);
|
|
1714
|
+
}
|
|
1715
|
+
const dimensionFilter = otherFilters.length > 0 || cleanedNestedGroups.length > 0 ? {
|
|
1716
|
+
...filter,
|
|
1717
|
+
_filters: otherFilters,
|
|
1718
|
+
_nestedGroups: cleanedNestedGroups.length > 0 ? cleanedNestedGroups : void 0
|
|
1719
|
+
} : void 0;
|
|
1720
|
+
return {
|
|
1721
|
+
startDate,
|
|
1722
|
+
endDate,
|
|
1723
|
+
searchType,
|
|
1724
|
+
dimensionFilter
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
function resolveToBodyResult(state) {
|
|
1728
|
+
const { startDate, endDate, searchType, dimensionFilter } = extractSpecialFilters(state.filter);
|
|
1729
|
+
if (!startDate || !endDate) return err(queryErrors.missingDateRange());
|
|
1730
|
+
const body = {
|
|
1731
|
+
dimensions: state.dimensions,
|
|
1732
|
+
startDate,
|
|
1733
|
+
endDate
|
|
1734
|
+
};
|
|
1735
|
+
const resolvedType = state.searchType ?? searchType;
|
|
1736
|
+
if (resolvedType) body.type = resolvedType;
|
|
1737
|
+
if (state.rowLimit !== void 0) {
|
|
1738
|
+
if (!Number.isInteger(state.rowLimit) || state.rowLimit < 1) return err(queryErrors.invalidRowLimit(state.rowLimit));
|
|
1739
|
+
body.rowLimit = state.rowLimit;
|
|
1740
|
+
}
|
|
1741
|
+
if (state.startRow !== void 0) {
|
|
1742
|
+
if (!Number.isInteger(state.startRow) || state.startRow < 0) return err(queryErrors.invalidStartRow(state.startRow));
|
|
1743
|
+
if (state.startRow > 0) body.startRow = state.startRow;
|
|
1744
|
+
}
|
|
1745
|
+
const hasHour = state.dimensions?.includes("hour");
|
|
1746
|
+
if (hasHour && state.dataState !== "hourly_all") return err(queryErrors.hourDimensionRequiresHourlyState());
|
|
1747
|
+
if (state.dataState === "hourly_all" && !hasHour) return err(queryErrors.hourlyStateRequiresHourDimension());
|
|
1748
|
+
if (state.dataState) body.dataState = state.dataState;
|
|
1749
|
+
const filterGroups = resolveFilter(dimensionFilter);
|
|
1750
|
+
if (filterGroups.length > 0) body.dimensionFilterGroups = filterGroups;
|
|
1751
|
+
if (state.aggregationType) {
|
|
1752
|
+
const groupsByPage = (body.dimensions ?? []).includes("page");
|
|
1753
|
+
const apiLeafFilters = filterGroups.flatMap((g) => g.filters ?? []);
|
|
1754
|
+
const filtersByPage = apiLeafFilters.some((f) => f.dimension === "page");
|
|
1755
|
+
if (state.aggregationType === "byProperty") {
|
|
1756
|
+
if (body.type === "discover" || body.type === "googleNews") return err(queryErrors.byPropertyUnsupportedSearchType());
|
|
1757
|
+
if (groupsByPage || filtersByPage) return err(queryErrors.byPropertyNotAllowedWithPage());
|
|
1758
|
+
}
|
|
1759
|
+
if (state.aggregationType === "byNewsShowcasePanel") {
|
|
1760
|
+
if (body.type !== "discover" && body.type !== "googleNews") return err(queryErrors.byNewsShowcaseRequiresSearchType());
|
|
1761
|
+
if (groupsByPage || filtersByPage) return err(queryErrors.byNewsShowcaseNotAllowedWithPage());
|
|
1762
|
+
const saFilters = apiLeafFilters.filter((f) => f.dimension === "searchAppearance");
|
|
1763
|
+
const hasNewsShowcase = saFilters.some((f) => f.operator === "equals" && f.expression === "NEWS_SHOWCASE");
|
|
1764
|
+
const hasOther = saFilters.some((f) => !(f.operator === "equals" && f.expression === "NEWS_SHOWCASE"));
|
|
1765
|
+
if (!hasNewsShowcase || hasOther) return err(queryErrors.byNewsShowcaseRequiresShowcaseFilter());
|
|
1766
|
+
}
|
|
1767
|
+
body.aggregationType = state.aggregationType;
|
|
1768
|
+
}
|
|
1769
|
+
return ok(body);
|
|
1770
|
+
}
|
|
1771
|
+
function resolveToBody(state) {
|
|
1772
|
+
return unwrapResult(resolveToBodyResult(state), queryErrorToException);
|
|
1773
|
+
}
|
|
1774
|
+
function isApiFilter(f) {
|
|
1775
|
+
return !isMetricOperator(f.operator) && !isSpecialOperator(f.operator);
|
|
1776
|
+
}
|
|
1777
|
+
function resolveFilter(filter) {
|
|
1778
|
+
if (!filter) return [];
|
|
1779
|
+
const groups = [];
|
|
1780
|
+
const groupType = filter._groupType ?? "and";
|
|
1781
|
+
const apiFilters = filter._filters.filter(isApiFilter);
|
|
1782
|
+
if (groupType === "or") {
|
|
1783
|
+
if (apiFilters.length > 0) groups.push({
|
|
1784
|
+
groupType: "or",
|
|
1785
|
+
filters: apiFilters.map((f) => ({
|
|
1786
|
+
dimension: f.dimension,
|
|
1787
|
+
operator: f.operator,
|
|
1788
|
+
expression: f.expression
|
|
1789
|
+
}))
|
|
1790
|
+
});
|
|
1791
|
+
} else if (apiFilters.length > 0) groups.push({ filters: apiFilters.map((f) => ({
|
|
1792
|
+
dimension: f.dimension,
|
|
1793
|
+
operator: f.operator,
|
|
1794
|
+
expression: f.expression
|
|
1795
|
+
})) });
|
|
1796
|
+
if (filter._nestedGroups) for (const nested of filter._nestedGroups) groups.push(...resolveFilter(nested));
|
|
1797
|
+
return groups;
|
|
1798
|
+
}
|
|
1799
|
+
function rowWithMetricDefaults(row) {
|
|
1800
|
+
return {
|
|
1801
|
+
clicks: row.clicks ?? 0,
|
|
1802
|
+
impressions: row.impressions ?? 0,
|
|
1803
|
+
ctr: row.ctr ?? 0,
|
|
1804
|
+
position: row.position ?? 0
|
|
1805
|
+
};
|
|
1806
|
+
}
|
|
1807
|
+
const TRAILING_SLASH_RE = /\/$/;
|
|
1808
|
+
function gscdumpApi(options) {
|
|
1809
|
+
const baseUrl = options.baseUrl?.replace(TRAILING_SLASH_RE, "") || "https://gscdump.com";
|
|
1810
|
+
const fetch = ofetch.create({
|
|
1811
|
+
baseURL: baseUrl,
|
|
1812
|
+
retry: 3,
|
|
1813
|
+
retryDelay: 1e3,
|
|
1814
|
+
retryStatusCodes: [
|
|
1815
|
+
408,
|
|
1816
|
+
409,
|
|
1817
|
+
425,
|
|
1818
|
+
429,
|
|
1819
|
+
500,
|
|
1820
|
+
502,
|
|
1821
|
+
503,
|
|
1822
|
+
504
|
|
1823
|
+
],
|
|
1824
|
+
headers: {
|
|
1825
|
+
"x-api-key": options.apiKey,
|
|
1826
|
+
"Content-Type": "application/json"
|
|
1827
|
+
}
|
|
1828
|
+
});
|
|
1829
|
+
const rawQuery = async (siteId, body, opts) => {
|
|
1830
|
+
const response = await fetch(`/api/sites/${encodeURIComponent(siteId)}/query`, {
|
|
1831
|
+
method: "POST",
|
|
1832
|
+
body,
|
|
1833
|
+
signal: opts?.signal
|
|
1834
|
+
});
|
|
1835
|
+
return { rows: response.rows.map((row) => {
|
|
1836
|
+
return {
|
|
1837
|
+
keys: response.meta.dimensions.map((dim) => String(row[dim] ?? "")),
|
|
1838
|
+
clicks: row.clicks,
|
|
1839
|
+
impressions: row.impressions,
|
|
1840
|
+
ctr: row.ctr,
|
|
1841
|
+
position: row.position
|
|
1842
|
+
};
|
|
1843
|
+
}) };
|
|
1844
|
+
};
|
|
1845
|
+
return {
|
|
1846
|
+
async *query(siteId, builder, opts) {
|
|
1847
|
+
const state = builder.getState();
|
|
1848
|
+
const body = resolveToBody(state);
|
|
1849
|
+
const totalCap = body.rowLimit;
|
|
1850
|
+
const pageSize = Math.min(totalCap ?? 25e3, 25e3);
|
|
1851
|
+
let startRow = body.startRow || 0;
|
|
1852
|
+
let yielded = 0;
|
|
1853
|
+
let metadata;
|
|
1854
|
+
while (true) {
|
|
1855
|
+
opts?.signal?.throwIfAborted();
|
|
1856
|
+
const remaining = totalCap ? totalCap - yielded : pageSize;
|
|
1857
|
+
if (remaining <= 0) break;
|
|
1858
|
+
const rowLimit = Math.min(pageSize, remaining);
|
|
1859
|
+
const response = await fetch(`/api/sites/${encodeURIComponent(siteId)}/query`, {
|
|
1860
|
+
method: "POST",
|
|
1861
|
+
body: {
|
|
1862
|
+
...body,
|
|
1863
|
+
startRow,
|
|
1864
|
+
rowLimit
|
|
1865
|
+
},
|
|
1866
|
+
signal: opts?.signal
|
|
1867
|
+
});
|
|
1868
|
+
if (response.metadata) metadata = response.metadata;
|
|
1869
|
+
const rows = response.rows.map((row) => {
|
|
1870
|
+
const result = rowWithMetricDefaults(row);
|
|
1871
|
+
state.dimensions.forEach((dim) => {
|
|
1872
|
+
result[dim] = row[dim];
|
|
1873
|
+
});
|
|
1874
|
+
return result;
|
|
1875
|
+
});
|
|
1876
|
+
yield rows;
|
|
1877
|
+
yielded += rows.length;
|
|
1878
|
+
if (!response.meta.hasMore || rows.length < rowLimit) break;
|
|
1879
|
+
startRow += rows.length;
|
|
1880
|
+
}
|
|
1881
|
+
return { metadata };
|
|
1882
|
+
},
|
|
1883
|
+
sites: (() => {
|
|
1884
|
+
const list = async (opts) => {
|
|
1885
|
+
return (await fetch("/api/sites", { signal: opts?.signal })).sites.map((s) => ({
|
|
1886
|
+
siteUrl: s.gscSiteUrl,
|
|
1887
|
+
permissionLevel: s.permissionLevel || "siteOwner"
|
|
1888
|
+
}));
|
|
1889
|
+
};
|
|
1890
|
+
const unsupported = (op) => () => {
|
|
1891
|
+
throw new Error(`sites.${op} not available via gscdump API. Use googleSearchConsole() with OAuth credentials.`);
|
|
1892
|
+
};
|
|
1893
|
+
return Object.assign(list, {
|
|
1894
|
+
list,
|
|
1895
|
+
get: unsupported("get"),
|
|
1896
|
+
add: unsupported("add"),
|
|
1897
|
+
delete: unsupported("delete")
|
|
1898
|
+
});
|
|
1899
|
+
})(),
|
|
1900
|
+
verification: {
|
|
1901
|
+
getToken: () => {
|
|
1902
|
+
throw new Error("Site Verification API not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1903
|
+
},
|
|
1904
|
+
insert: () => {
|
|
1905
|
+
throw new Error("Site Verification API not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1906
|
+
},
|
|
1907
|
+
list: () => {
|
|
1908
|
+
throw new Error("Site Verification API not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1909
|
+
},
|
|
1910
|
+
get: () => {
|
|
1911
|
+
throw new Error("Site Verification API not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1912
|
+
},
|
|
1913
|
+
delete: () => {
|
|
1914
|
+
throw new Error("Site Verification API not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1915
|
+
}
|
|
1916
|
+
},
|
|
1917
|
+
inspect: () => {
|
|
1918
|
+
throw new Error("URL inspection not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1919
|
+
},
|
|
1920
|
+
sitemaps: {
|
|
1921
|
+
list: async (siteId, opts) => {
|
|
1922
|
+
return (await fetch(`/api/sites/${encodeURIComponent(siteId)}/sitemaps`, { signal: opts?.signal })).sitemaps || [];
|
|
1923
|
+
},
|
|
1924
|
+
get: () => {
|
|
1925
|
+
throw new Error("Sitemap get not available via gscdump API.");
|
|
1926
|
+
},
|
|
1927
|
+
submit: () => {
|
|
1928
|
+
throw new Error("Sitemap submit not available via gscdump API.");
|
|
1929
|
+
},
|
|
1930
|
+
delete: () => {
|
|
1931
|
+
throw new Error("Sitemap delete not available via gscdump API.");
|
|
1932
|
+
}
|
|
1933
|
+
},
|
|
1934
|
+
indexing: {
|
|
1935
|
+
publish: () => {
|
|
1936
|
+
throw new Error("Indexing API not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1937
|
+
},
|
|
1938
|
+
getMetadata: () => {
|
|
1939
|
+
throw new Error("Indexing API not available via gscdump API. Use googleSearchConsole() with OAuth credentials.");
|
|
1940
|
+
}
|
|
1941
|
+
},
|
|
1942
|
+
_rawQuery: rawQuery
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
const GSC_API = "https://searchconsole.googleapis.com";
|
|
1946
|
+
const INDEXING_API = "https://indexing.googleapis.com";
|
|
1947
|
+
const SITE_VERIFICATION_API = "https://www.googleapis.com/siteVerification/v1";
|
|
1948
|
+
function encodeSiteUrl(siteUrl) {
|
|
1949
|
+
if (siteUrl.startsWith("sc-domain:")) return `sc-domain:${encodeURIComponent(siteUrl.slice(10))}`;
|
|
1950
|
+
return encodeURIComponent(siteUrl);
|
|
1951
|
+
}
|
|
1952
|
+
function assertValidSiteUrl(siteUrl) {
|
|
1953
|
+
if (siteUrl.startsWith("sc-domain:") && siteUrl.length > 10) return;
|
|
1954
|
+
if (/^https?:\/\/.+/.test(siteUrl)) return;
|
|
1955
|
+
throw new Error(`Invalid siteUrl: expected "https?://…" or "sc-domain:…", got "${siteUrl}"`);
|
|
1956
|
+
}
|
|
1957
|
+
function createAuth(options) {
|
|
1958
|
+
let credentials = { refresh_token: options.refreshToken };
|
|
1959
|
+
return {
|
|
1960
|
+
get credentials() {
|
|
1961
|
+
return credentials;
|
|
1962
|
+
},
|
|
1963
|
+
async getAccessToken() {
|
|
1964
|
+
if (credentials?.access_token && credentials.expiry_date && credentials.expiry_date > Date.now()) return { token: credentials.access_token };
|
|
1965
|
+
const response = await ofetch("https://oauth2.googleapis.com/token", {
|
|
1966
|
+
method: "POST",
|
|
1967
|
+
body: {
|
|
1968
|
+
client_id: options.clientId,
|
|
1969
|
+
client_secret: options.clientSecret,
|
|
1970
|
+
refresh_token: options.refreshToken,
|
|
1971
|
+
grant_type: "refresh_token"
|
|
1972
|
+
}
|
|
1973
|
+
});
|
|
1974
|
+
credentials = {
|
|
1975
|
+
...credentials,
|
|
1976
|
+
access_token: response.access_token,
|
|
1977
|
+
expiry_date: Date.now() + response.expires_in * 1e3
|
|
1978
|
+
};
|
|
1979
|
+
return { token: response.access_token };
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
async function resolveToken(auth) {
|
|
1984
|
+
if (typeof auth === "string") return auth;
|
|
1985
|
+
if ("accessToken" in auth && typeof auth.accessToken === "string") return auth.accessToken;
|
|
1986
|
+
if ("getAccessToken" in auth && typeof auth.getAccessToken === "function") {
|
|
1987
|
+
const { token } = await auth.getAccessToken();
|
|
1988
|
+
return token || "";
|
|
1989
|
+
}
|
|
1990
|
+
if ("credentials" in auth && auth.credentials) return auth.credentials.access_token || "";
|
|
1991
|
+
return "";
|
|
1992
|
+
}
|
|
1993
|
+
function createFetch(auth, options) {
|
|
1994
|
+
const authState = typeof auth === "object" && auth !== null && "clientId" in auth && "refreshToken" in auth && !("getAccessToken" in auth) ? createAuth(auth) : auth;
|
|
1995
|
+
return ofetch.create({
|
|
1996
|
+
...options,
|
|
1997
|
+
retry: 3,
|
|
1998
|
+
retryDelay: (ctx) => {
|
|
1999
|
+
const status = ctx.response?.status;
|
|
2000
|
+
if (status === 429 || status === 503) {
|
|
2001
|
+
const header = ctx.response?.headers.get("retry-after");
|
|
2002
|
+
if (header) {
|
|
2003
|
+
const secs = Number.parseInt(header, 10);
|
|
2004
|
+
if (Number.isFinite(secs)) return secs * 1e3;
|
|
2005
|
+
const when = Date.parse(header);
|
|
2006
|
+
if (Number.isFinite(when)) return Math.max(0, when - Date.now());
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
return 1e3;
|
|
2010
|
+
},
|
|
2011
|
+
retryStatusCodes: [
|
|
2012
|
+
408,
|
|
2013
|
+
425,
|
|
2014
|
+
429,
|
|
2015
|
+
500,
|
|
2016
|
+
502,
|
|
2017
|
+
503,
|
|
2018
|
+
504
|
|
2019
|
+
],
|
|
2020
|
+
headers: {
|
|
2021
|
+
...options?.headers,
|
|
2022
|
+
"Accept-Encoding": "gzip",
|
|
2023
|
+
"User-Agent": "gscdump (gzip)"
|
|
2024
|
+
},
|
|
2025
|
+
async onRequest({ options }) {
|
|
2026
|
+
const token = await resolveToken(authState);
|
|
2027
|
+
if (token) {
|
|
2028
|
+
options.headers = new Headers(options.headers);
|
|
2029
|
+
options.headers.set("Authorization", `Bearer ${token}`);
|
|
2030
|
+
}
|
|
2031
|
+
},
|
|
2032
|
+
async onResponseError(ctx) {
|
|
2033
|
+
if (ctx.response.status === 403) console.error("[gscdump] Permission denied (403). check your service account permissions being added to the GSC property.");
|
|
2034
|
+
if (options?.onResponseError) if (Array.isArray(options.onResponseError)) for (const handler of options.onResponseError) await handler(ctx);
|
|
2035
|
+
else await options.onResponseError(ctx);
|
|
2036
|
+
}
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
function googleSearchConsole(auth, options = {}) {
|
|
2040
|
+
let fetch;
|
|
2041
|
+
const authState = typeof auth === "object" && auth !== null && "clientId" in auth && "refreshToken" in auth && !("getAccessToken" in auth) ? createAuth(auth) : auth;
|
|
2042
|
+
if (options.fetch) fetch = options.fetch;
|
|
2043
|
+
else {
|
|
2044
|
+
const fetchOptions = options.fetchOptions || {};
|
|
2045
|
+
if (options.onRateLimited) {
|
|
2046
|
+
const originalOnError = fetchOptions.onResponseError;
|
|
2047
|
+
fetchOptions.onResponseError = async (ctx) => {
|
|
2048
|
+
if (ctx.response.status === 429) await options.onRateLimited({ response: ctx.response });
|
|
2049
|
+
if (originalOnError) if (Array.isArray(originalOnError)) for (const handler of originalOnError) await handler(ctx);
|
|
2050
|
+
else await originalOnError(ctx);
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
fetch = createFetch(authState, fetchOptions);
|
|
2054
|
+
}
|
|
2055
|
+
const rawQuery = (siteUrl, body, opts) => fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}/searchAnalytics/query`, {
|
|
2056
|
+
method: "POST",
|
|
2057
|
+
body,
|
|
2058
|
+
signal: opts?.signal
|
|
2059
|
+
});
|
|
2060
|
+
return {
|
|
2061
|
+
async *query(siteUrl, builder, opts) {
|
|
2062
|
+
const state = builder.getState();
|
|
2063
|
+
const body = resolveToBody(state);
|
|
2064
|
+
const totalCap = body.rowLimit;
|
|
2065
|
+
const pageSize = Math.min(totalCap ?? 25e3, 25e3);
|
|
2066
|
+
let startRow = body.startRow || 0;
|
|
2067
|
+
let yielded = 0;
|
|
2068
|
+
let metadata;
|
|
2069
|
+
let responseAggregationType;
|
|
2070
|
+
while (true) {
|
|
2071
|
+
opts?.signal?.throwIfAborted();
|
|
2072
|
+
const remaining = totalCap ? totalCap - yielded : pageSize;
|
|
2073
|
+
if (remaining <= 0) break;
|
|
2074
|
+
const rowLimit = Math.min(pageSize, remaining);
|
|
2075
|
+
const response = await rawQuery(siteUrl, {
|
|
2076
|
+
...body,
|
|
2077
|
+
startRow,
|
|
2078
|
+
rowLimit
|
|
2079
|
+
}, opts);
|
|
2080
|
+
if (response.metadata) metadata = response.metadata;
|
|
2081
|
+
if (response.responseAggregationType) responseAggregationType = response.responseAggregationType;
|
|
2082
|
+
const rows = (response.rows || []).map((row) => {
|
|
2083
|
+
const result = rowWithMetricDefaults(row);
|
|
2084
|
+
state.dimensions.forEach((dim, i) => {
|
|
2085
|
+
result[dim] = row.keys?.[i];
|
|
2086
|
+
});
|
|
2087
|
+
return result;
|
|
2088
|
+
});
|
|
2089
|
+
if (rows.length === 0) break;
|
|
2090
|
+
yield rows;
|
|
2091
|
+
yielded += rows.length;
|
|
2092
|
+
startRow += rows.length;
|
|
2093
|
+
}
|
|
2094
|
+
return {
|
|
2095
|
+
metadata,
|
|
2096
|
+
responseAggregationType
|
|
2097
|
+
};
|
|
2098
|
+
},
|
|
2099
|
+
sites: (() => {
|
|
2100
|
+
const list = async (opts) => {
|
|
2101
|
+
return (await fetch(`${GSC_API}/webmasters/v3/sites`, { signal: opts?.signal })).siteEntry || [];
|
|
2102
|
+
};
|
|
2103
|
+
return Object.assign(list, {
|
|
2104
|
+
list,
|
|
2105
|
+
get: (siteUrl, opts) => fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}`, { signal: opts?.signal }),
|
|
2106
|
+
add: (siteUrl, opts) => {
|
|
2107
|
+
assertValidSiteUrl(siteUrl);
|
|
2108
|
+
return fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}`, {
|
|
2109
|
+
method: "PUT",
|
|
2110
|
+
signal: opts?.signal
|
|
2111
|
+
});
|
|
2112
|
+
},
|
|
2113
|
+
delete: (siteUrl, opts) => fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}`, {
|
|
2114
|
+
method: "DELETE",
|
|
2115
|
+
signal: opts?.signal
|
|
2116
|
+
})
|
|
2117
|
+
});
|
|
2118
|
+
})(),
|
|
2119
|
+
verification: {
|
|
2120
|
+
getToken: (params, opts) => fetch(`${SITE_VERIFICATION_API}/token`, {
|
|
2121
|
+
method: "POST",
|
|
2122
|
+
body: params,
|
|
2123
|
+
signal: opts?.signal
|
|
2124
|
+
}),
|
|
2125
|
+
insert: (params, opts) => fetch(`${SITE_VERIFICATION_API}/webResource`, {
|
|
2126
|
+
method: "POST",
|
|
2127
|
+
query: { verificationMethod: params.verificationMethod },
|
|
2128
|
+
body: { site: params.site },
|
|
2129
|
+
signal: opts?.signal
|
|
2130
|
+
}),
|
|
2131
|
+
list: async (opts) => {
|
|
2132
|
+
return (await fetch(`${SITE_VERIFICATION_API}/webResource`, { signal: opts?.signal })).items || [];
|
|
2133
|
+
},
|
|
2134
|
+
get: (id, opts) => fetch(`${SITE_VERIFICATION_API}/webResource/${encodeURIComponent(id)}`, { signal: opts?.signal }),
|
|
2135
|
+
delete: (id, opts) => fetch(`${SITE_VERIFICATION_API}/webResource/${encodeURIComponent(id)}`, {
|
|
2136
|
+
method: "DELETE",
|
|
2137
|
+
signal: opts?.signal
|
|
2138
|
+
})
|
|
2139
|
+
},
|
|
2140
|
+
inspect: (siteUrl, url, opts) => fetch(`${GSC_API}/v1/urlInspection/index:inspect`, {
|
|
2141
|
+
method: "POST",
|
|
2142
|
+
body: opts?.languageCode ? {
|
|
2143
|
+
inspectionUrl: url,
|
|
2144
|
+
siteUrl,
|
|
2145
|
+
languageCode: opts.languageCode
|
|
2146
|
+
} : {
|
|
2147
|
+
inspectionUrl: url,
|
|
2148
|
+
siteUrl
|
|
2149
|
+
},
|
|
2150
|
+
signal: opts?.signal
|
|
2151
|
+
}),
|
|
2152
|
+
sitemaps: {
|
|
2153
|
+
list: async (siteUrl, opts) => {
|
|
2154
|
+
return (await fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}/sitemaps`, {
|
|
2155
|
+
signal: opts?.signal,
|
|
2156
|
+
query: opts?.sitemapIndex ? { sitemapIndex: opts.sitemapIndex } : void 0
|
|
2157
|
+
})).sitemap || [];
|
|
2158
|
+
},
|
|
2159
|
+
get: (siteUrl, feedpath, opts) => fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}/sitemaps/${encodeURIComponent(feedpath)}`, { signal: opts?.signal }),
|
|
2160
|
+
submit: (siteUrl, feedpath, opts) => fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}/sitemaps/${encodeURIComponent(feedpath)}`, {
|
|
2161
|
+
method: "PUT",
|
|
2162
|
+
signal: opts?.signal
|
|
2163
|
+
}),
|
|
2164
|
+
delete: (siteUrl, feedpath, opts) => fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}/sitemaps/${encodeURIComponent(feedpath)}`, {
|
|
2165
|
+
method: "DELETE",
|
|
2166
|
+
signal: opts?.signal
|
|
2167
|
+
})
|
|
2168
|
+
},
|
|
2169
|
+
indexing: {
|
|
2170
|
+
publish: (url, type, opts) => fetch(`${INDEXING_API}/v3/urlNotifications:publish`, {
|
|
2171
|
+
method: "POST",
|
|
2172
|
+
body: {
|
|
2173
|
+
url,
|
|
2174
|
+
type
|
|
2175
|
+
},
|
|
2176
|
+
signal: opts?.signal
|
|
2177
|
+
}),
|
|
2178
|
+
getMetadata: (url, opts) => fetch(`${INDEXING_API}/v3/urlNotifications/metadata`, {
|
|
2179
|
+
query: { url },
|
|
2180
|
+
signal: opts?.signal
|
|
2181
|
+
})
|
|
2182
|
+
},
|
|
2183
|
+
_rawQuery: rawQuery
|
|
2184
|
+
};
|
|
2185
|
+
}
|
|
2186
|
+
const GSC_QUOTAS = {
|
|
2187
|
+
searchAnalytics: 25e3,
|
|
2188
|
+
urlInspection: 2e3,
|
|
2189
|
+
indexing: 200
|
|
2190
|
+
};
|
|
2191
|
+
function pickField(error, paths, is) {
|
|
2192
|
+
if (!error || typeof error !== "object") return void 0;
|
|
2193
|
+
for (const path of paths) {
|
|
2194
|
+
let current = error;
|
|
2195
|
+
for (const key of path) {
|
|
2196
|
+
if (!current || typeof current !== "object") {
|
|
2197
|
+
current = void 0;
|
|
2198
|
+
break;
|
|
2199
|
+
}
|
|
2200
|
+
current = current[key];
|
|
2201
|
+
}
|
|
2202
|
+
if (is(current)) return current;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
const isNumber = (v) => typeof v === "number";
|
|
2206
|
+
const isString = (v) => typeof v === "string";
|
|
2207
|
+
function extractStatus(error) {
|
|
2208
|
+
return pickField(error, [
|
|
2209
|
+
["statusCode"],
|
|
2210
|
+
["status"],
|
|
2211
|
+
["response", "status"],
|
|
2212
|
+
["code"]
|
|
2213
|
+
], isNumber);
|
|
2214
|
+
}
|
|
2215
|
+
function extractMessage(error) {
|
|
2216
|
+
if (!error) return "Unknown error";
|
|
2217
|
+
if (typeof error === "string") return error;
|
|
2218
|
+
if (error instanceof Error) return error.message;
|
|
2219
|
+
if (typeof error !== "object") return String(error);
|
|
2220
|
+
return pickField(error, [
|
|
2221
|
+
[
|
|
2222
|
+
"data",
|
|
2223
|
+
"error",
|
|
2224
|
+
"message"
|
|
2225
|
+
],
|
|
2226
|
+
["message"],
|
|
2227
|
+
["statusMessage"]
|
|
2228
|
+
], isString) ?? String(error);
|
|
2229
|
+
}
|
|
2230
|
+
function extractRetryAfter(error) {
|
|
2231
|
+
const raw = pickField(error, [
|
|
2232
|
+
["headers", "retry-after"],
|
|
2233
|
+
["headers", "Retry-After"],
|
|
2234
|
+
[
|
|
2235
|
+
"response",
|
|
2236
|
+
"headers",
|
|
2237
|
+
"retry-after"
|
|
2238
|
+
],
|
|
2239
|
+
[
|
|
2240
|
+
"response",
|
|
2241
|
+
"headers",
|
|
2242
|
+
"Retry-After"
|
|
2243
|
+
]
|
|
2244
|
+
], (v) => typeof v === "number" || typeof v === "string");
|
|
2245
|
+
if (typeof raw === "number") return raw;
|
|
2246
|
+
if (typeof raw === "string") {
|
|
2247
|
+
const seconds = Number.parseInt(raw, 10);
|
|
2248
|
+
return Number.isNaN(seconds) ? void 0 : seconds;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
const QUOTA_MESSAGE_RE = /quota|rate\s*limit/i;
|
|
2252
|
+
const QUOTA_REASONS = new Set([
|
|
2253
|
+
"dailyLimitExceeded",
|
|
2254
|
+
"dailyLimitExceededUnreg",
|
|
2255
|
+
"rateLimitExceeded",
|
|
2256
|
+
"rateLimitExceededUnreg",
|
|
2257
|
+
"userRateLimitExceeded",
|
|
2258
|
+
"userRateLimitExceededUnreg",
|
|
2259
|
+
"quotaExceeded",
|
|
2260
|
+
"concurrentLimitExceeded",
|
|
2261
|
+
"variableTermLimitExceeded",
|
|
2262
|
+
"variableTermExpiredDailyExceeded",
|
|
2263
|
+
"servingLimitExceeded",
|
|
2264
|
+
"responseTooLarge",
|
|
2265
|
+
"limitExceeded",
|
|
2266
|
+
"batchSizeTooLarge",
|
|
2267
|
+
"RATE_LIMIT_EXCEEDED",
|
|
2268
|
+
"RESOURCE_EXHAUSTED"
|
|
2269
|
+
]);
|
|
2270
|
+
function extractReason(cause) {
|
|
2271
|
+
const data = pickField(cause, [["data"]], (_v) => true);
|
|
2272
|
+
if (data) {
|
|
2273
|
+
const errorInfo = pickField(data, [["error", "details"]], (v) => Array.isArray(v));
|
|
2274
|
+
if (errorInfo) {
|
|
2275
|
+
const reason = errorInfo.find((d) => typeof d["@type"] === "string" && d["@type"].includes("ErrorInfo"))?.reason;
|
|
2276
|
+
if (typeof reason === "string") return reason;
|
|
2277
|
+
}
|
|
2278
|
+
const directErrors = pickField(data, [["error", "errors"]], (v) => Array.isArray(v));
|
|
2279
|
+
if (directErrors) {
|
|
2280
|
+
const reason = directErrors[0]?.reason;
|
|
2281
|
+
if (typeof reason === "string") return reason;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
function isQuotaCondition(cause, message) {
|
|
2286
|
+
const reason = extractReason(cause);
|
|
2287
|
+
if (reason && QUOTA_REASONS.has(reason)) return true;
|
|
2288
|
+
return QUOTA_MESSAGE_RE.test(message);
|
|
2289
|
+
}
|
|
2290
|
+
function classifyError(cause) {
|
|
2291
|
+
const status = extractStatus(cause);
|
|
2292
|
+
const message = extractMessage(cause);
|
|
2293
|
+
if (status === 401) return {
|
|
2294
|
+
kind: "auth-expired",
|
|
2295
|
+
message,
|
|
2296
|
+
cause
|
|
2297
|
+
};
|
|
2298
|
+
if (status === 429) return {
|
|
2299
|
+
kind: "rate-limited",
|
|
2300
|
+
message,
|
|
2301
|
+
retryAfter: extractRetryAfter(cause),
|
|
2302
|
+
cause
|
|
2303
|
+
};
|
|
2304
|
+
if (status === 403) {
|
|
2305
|
+
if (isQuotaCondition(cause, message)) return {
|
|
2306
|
+
kind: "rate-limited",
|
|
2307
|
+
message,
|
|
2308
|
+
retryAfter: extractRetryAfter(cause),
|
|
2309
|
+
cause
|
|
2310
|
+
};
|
|
2311
|
+
return {
|
|
2312
|
+
kind: "auth-expired",
|
|
2313
|
+
message,
|
|
2314
|
+
cause
|
|
2315
|
+
};
|
|
2316
|
+
}
|
|
2317
|
+
if (status === 404 || status === 410) return {
|
|
2318
|
+
kind: "not-found",
|
|
2319
|
+
message,
|
|
2320
|
+
cause
|
|
2321
|
+
};
|
|
2322
|
+
if (status === 400 || status === 402 || status === 409 || status === 413 || status === 422) return {
|
|
2323
|
+
kind: "validation",
|
|
2324
|
+
message,
|
|
2325
|
+
cause
|
|
2326
|
+
};
|
|
2327
|
+
return {
|
|
2328
|
+
kind: "transport",
|
|
2329
|
+
message,
|
|
2330
|
+
status,
|
|
2331
|
+
cause
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
function storageError(message, cause) {
|
|
2335
|
+
return {
|
|
2336
|
+
kind: "storage",
|
|
2337
|
+
message,
|
|
2338
|
+
cause
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
function gscErrorToException(error) {
|
|
2342
|
+
const exception = new Error(error.message);
|
|
2343
|
+
if (error.cause !== void 0) exception.cause = error.cause;
|
|
2344
|
+
exception.gscError = error;
|
|
2345
|
+
return exception;
|
|
2346
|
+
}
|
|
2347
|
+
function parseGoogleError(text, httpStatus) {
|
|
2348
|
+
let parsed = null;
|
|
2349
|
+
try {
|
|
2350
|
+
parsed = JSON.parse(text);
|
|
2351
|
+
} catch {}
|
|
2352
|
+
if (!parsed || !("error" in parsed)) return {
|
|
2353
|
+
code: httpStatus ?? 500,
|
|
2354
|
+
message: text || "Unknown Google API error"
|
|
2355
|
+
};
|
|
2356
|
+
if (typeof parsed.error === "string") {
|
|
2357
|
+
const oauth = parsed;
|
|
2358
|
+
return {
|
|
2359
|
+
code: httpStatus ?? 400,
|
|
2360
|
+
message: oauth.error_description || oauth.error,
|
|
2361
|
+
reason: oauth.error
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
const err = parsed.error;
|
|
2365
|
+
const errorInfo = err.details?.find((d) => d["@type"]?.includes("ErrorInfo"));
|
|
2366
|
+
return {
|
|
2367
|
+
code: err.code ?? httpStatus ?? 500,
|
|
2368
|
+
message: err.message || err.status || text || `HTTP ${httpStatus ?? "?"}`,
|
|
2369
|
+
reason: errorInfo?.reason,
|
|
2370
|
+
status: err.status
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
var GscApiError = class extends Error {
|
|
2374
|
+
info;
|
|
2375
|
+
constructor(message, info) {
|
|
2376
|
+
super(message);
|
|
2377
|
+
this.info = info;
|
|
2378
|
+
this.name = "GscApiError";
|
|
2379
|
+
}
|
|
2380
|
+
};
|
|
2381
|
+
function rethrowAsGscApiError(prefix) {
|
|
2382
|
+
return (err) => {
|
|
2383
|
+
if (err instanceof GscApiError) throw err;
|
|
2384
|
+
const maybe = err;
|
|
2385
|
+
if (maybe && maybe.name === "FetchError") {
|
|
2386
|
+
const info = parseGoogleError(typeof maybe.data === "string" ? maybe.data : JSON.stringify(maybe.data ?? {}), maybe.statusCode);
|
|
2387
|
+
throw new GscApiError(`${prefix}: ${info.message}`, info);
|
|
2388
|
+
}
|
|
2389
|
+
throw err;
|
|
2390
|
+
};
|
|
2391
|
+
}
|
|
2392
|
+
const PERMISSION_SIGNALS = [
|
|
2393
|
+
"403 forbidden",
|
|
2394
|
+
"permission_denied",
|
|
2395
|
+
"does not have sufficient permission",
|
|
2396
|
+
"insufficient permission"
|
|
2397
|
+
];
|
|
2398
|
+
function isPermissionDeniedError(err) {
|
|
2399
|
+
const msg = String(err?.message ?? err ?? "").toLowerCase();
|
|
2400
|
+
return PERMISSION_SIGNALS.some((s) => msg.includes(s));
|
|
2401
|
+
}
|
|
2402
|
+
function suggestionFor(err) {
|
|
2403
|
+
switch (err.kind) {
|
|
2404
|
+
case "auth-expired": return "Run `gscdump auth` to re-authenticate.";
|
|
2405
|
+
case "rate-limited": {
|
|
2406
|
+
const retryIn = err.retryAfter ? `${err.retryAfter}s` : "a few minutes";
|
|
2407
|
+
if (QUOTA_MESSAGE_RE.test(err.message)) {
|
|
2408
|
+
if (err.message.includes("Indexing API")) return `Indexing API quota exhausted (~${GSC_QUOTAS.indexing}/day). Try again tomorrow.`;
|
|
2409
|
+
return `Quota or rate limit hit (Search Analytics ~${GSC_QUOTAS.searchAnalytics}/day). Try again in ${retryIn}.`;
|
|
2410
|
+
}
|
|
2411
|
+
return `Rate limited. Slow down requests. Try again in ${retryIn}.`;
|
|
2412
|
+
}
|
|
2413
|
+
case "not-found":
|
|
2414
|
+
case "validation":
|
|
2415
|
+
case "storage":
|
|
2416
|
+
case "transport": return "";
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
function formatErrorForCli(cause) {
|
|
2420
|
+
const err = classifyError(cause);
|
|
2421
|
+
const lines = [`\x1B[31m${err.message}\x1B[0m`];
|
|
2422
|
+
const suggestion = suggestionFor(err);
|
|
2423
|
+
if (suggestion) {
|
|
2424
|
+
lines.push("");
|
|
2425
|
+
lines.push(suggestion);
|
|
2426
|
+
}
|
|
2427
|
+
return lines.join("\n");
|
|
2428
|
+
}
|
|
2429
|
+
const SCHEME_RE = /^(sc-domain:|https?:\/\/)/;
|
|
2430
|
+
function parseGscSiteUrl(siteUrl) {
|
|
2431
|
+
const isDomain = siteUrl.startsWith("sc-domain:");
|
|
2432
|
+
let hostname = siteUrl;
|
|
2433
|
+
if (isDomain) hostname = siteUrl.slice(10);
|
|
2434
|
+
else try {
|
|
2435
|
+
hostname = new URL(siteUrl).hostname;
|
|
2436
|
+
} catch {
|
|
2437
|
+
hostname = siteUrl;
|
|
2438
|
+
}
|
|
2439
|
+
const displayLabel = siteUrl.replace(SCHEME_RE, "").replace(/\/$/, "");
|
|
2440
|
+
return {
|
|
2441
|
+
label: siteUrl,
|
|
2442
|
+
hostname,
|
|
2443
|
+
displayLabel,
|
|
2444
|
+
propertyType: isDomain ? "domain" : "url-prefix",
|
|
2445
|
+
isDomain
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
function normalizeGscSiteUrl(siteUrl) {
|
|
2449
|
+
return siteUrl.replace(/^sc-domain:/, "").replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/$/, "").toLowerCase();
|
|
2450
|
+
}
|
|
2451
|
+
function normalizeRegistrationTarget(inputUrl) {
|
|
2452
|
+
const trimmed = inputUrl.trim();
|
|
2453
|
+
if (!trimmed) return null;
|
|
2454
|
+
const inputParsed = parseGscSiteUrl(trimmed);
|
|
2455
|
+
if (inputParsed.isDomain) return inputParsed.hostname.toLowerCase();
|
|
2456
|
+
return trimmed.match(/^(?:https?:\/\/)?([^/]+)/)?.[1]?.toLowerCase() ?? null;
|
|
2457
|
+
}
|
|
2458
|
+
const VERIFIED_PERMISSIONS = new Set([
|
|
2459
|
+
"siteOwner",
|
|
2460
|
+
"siteFullUser",
|
|
2461
|
+
"siteRestrictedUser"
|
|
2462
|
+
]);
|
|
2463
|
+
function isVerifiedGscProperty(property) {
|
|
2464
|
+
return !!property?.permissionLevel && VERIFIED_PERMISSIONS.has(property.permissionLevel);
|
|
2465
|
+
}
|
|
2466
|
+
function isVerifiedGscPermission(level) {
|
|
2467
|
+
return !!level && VERIFIED_PERMISSIONS.has(level);
|
|
2468
|
+
}
|
|
2469
|
+
const stripWww = (d) => d.replace(/^www\./, "");
|
|
2470
|
+
function gscPropertyMatchesTarget(targetDomain, propertyUrl) {
|
|
2471
|
+
if (!propertyUrl) return false;
|
|
2472
|
+
const cleanTarget = stripWww(targetDomain);
|
|
2473
|
+
const parsed = parseGscSiteUrl(propertyUrl);
|
|
2474
|
+
if (parsed.isDomain) return cleanTarget === parsed.hostname || cleanTarget.endsWith(`.${parsed.hostname}`);
|
|
2475
|
+
const match = propertyUrl.match(/^https?:\/\/([^/]+)/);
|
|
2476
|
+
return !!match && stripWww(match[1].toLowerCase()) === cleanTarget;
|
|
2477
|
+
}
|
|
2478
|
+
function matchGscSite(siteUrl, gscSiteUrl) {
|
|
2479
|
+
if (!siteUrl || !gscSiteUrl) return false;
|
|
2480
|
+
const getHostname = (url) => {
|
|
2481
|
+
if (url.startsWith("sc-domain:")) return url.replace("sc-domain:", "");
|
|
2482
|
+
try {
|
|
2483
|
+
return new URL(url).hostname;
|
|
2484
|
+
} catch {
|
|
2485
|
+
return url;
|
|
2486
|
+
}
|
|
2487
|
+
};
|
|
2488
|
+
return gscPropertyMatchesTarget(getHostname(siteUrl), gscSiteUrl);
|
|
2489
|
+
}
|
|
2490
|
+
function pickBestGscProperty(origin, availableSites) {
|
|
2491
|
+
const matches = availableSites.filter((p) => matchGscSite(origin, p.siteUrl));
|
|
2492
|
+
if (!matches.length) return void 0;
|
|
2493
|
+
const isDomain = (p) => !!p.siteUrl?.startsWith("sc-domain:");
|
|
2494
|
+
const verified = matches.filter((p) => isVerifiedGscPermission(p.permissionLevel));
|
|
2495
|
+
const pool = verified.length ? verified : matches;
|
|
2496
|
+
return pool.find(isDomain) ?? pool[0];
|
|
2497
|
+
}
|
|
2498
|
+
function findBestGscProperty(targetDomain, properties) {
|
|
2499
|
+
const cleanTarget = stripWww(targetDomain);
|
|
2500
|
+
const domainProperty = properties.find((property) => {
|
|
2501
|
+
if (!property.siteUrl) return false;
|
|
2502
|
+
const parsed = parseGscSiteUrl(property.siteUrl);
|
|
2503
|
+
if (!parsed.isDomain) return false;
|
|
2504
|
+
return cleanTarget === parsed.hostname || cleanTarget.endsWith(`.${parsed.hostname}`);
|
|
2505
|
+
});
|
|
2506
|
+
const urlProperty = properties.find((property) => {
|
|
2507
|
+
if (!property.siteUrl) return false;
|
|
2508
|
+
const match = property.siteUrl.match(/^https?:\/\/([^/]+)/);
|
|
2509
|
+
return match && stripWww(match[1].toLowerCase()) === cleanTarget;
|
|
2510
|
+
});
|
|
2511
|
+
return {
|
|
2512
|
+
matchedSite: (isVerifiedGscProperty(domainProperty) ? domainProperty : isVerifiedGscProperty(urlProperty) ? urlProperty : domainProperty || urlProperty) ?? null,
|
|
2513
|
+
domainProperty: domainProperty ?? null,
|
|
2514
|
+
urlProperty: urlProperty ?? null
|
|
2515
|
+
};
|
|
2516
|
+
}
|
|
2517
|
+
function findExactGscProperty(propertyUrl, properties) {
|
|
2518
|
+
return properties.find((property) => property.siteUrl === propertyUrl) ?? null;
|
|
2519
|
+
}
|
|
2520
|
+
function formatGscPropertyCandidates(candidates) {
|
|
2521
|
+
return candidates.filter((c) => !!c).map((property) => `${property.siteUrl} (${property.permissionLevel})`).join(", ");
|
|
2522
|
+
}
|
|
2523
|
+
const URL_INSPECTION_DAILY_LIMIT = 2e3;
|
|
2524
|
+
const URL_INSPECTION_EFFECTIVE_LIMIT = 1800;
|
|
2525
|
+
const WEBMASTERS_READ = "https://www.googleapis.com/auth/webmasters.readonly";
|
|
2526
|
+
const WEBMASTERS_WRITE = "https://www.googleapis.com/auth/webmasters";
|
|
2527
|
+
const INDEXING = "https://www.googleapis.com/auth/indexing";
|
|
2528
|
+
function tokenize(scopes) {
|
|
2529
|
+
if (!scopes) return [];
|
|
2530
|
+
return scopes.split(/\s+/).filter(Boolean);
|
|
2531
|
+
}
|
|
2532
|
+
function hasScope(scopes, scope) {
|
|
2533
|
+
const tokens = tokenize(scopes);
|
|
2534
|
+
const suffix = scope.replace("https://www.googleapis.com/auth/", "");
|
|
2535
|
+
return tokens.includes(scope) || tokens.includes(suffix);
|
|
2536
|
+
}
|
|
2537
|
+
function hasGscReadScope(scopes) {
|
|
2538
|
+
return hasScope(scopes, WEBMASTERS_READ) || hasScope(scopes, WEBMASTERS_WRITE);
|
|
2539
|
+
}
|
|
2540
|
+
function hasGscWriteScope(scopes) {
|
|
2541
|
+
return hasScope(scopes, WEBMASTERS_WRITE);
|
|
2542
|
+
}
|
|
2543
|
+
function hasIndexingScope(scopes) {
|
|
2544
|
+
return hasScope(scopes, INDEXING);
|
|
2545
|
+
}
|
|
2546
|
+
const FETCH_TIMEOUT_MS = 1e4;
|
|
2547
|
+
const COMMON_PATHS = ["/sitemap.xml", "/sitemap_index.xml"];
|
|
2548
|
+
const SITEMAP_DIRECTIVE_RE = /^Sitemap:\s*(\S+)/im;
|
|
2549
|
+
async function discoverSitemap(domain, options = {}) {
|
|
2550
|
+
const userAgent = options.userAgent ?? "gscdump sitemap fetcher";
|
|
2551
|
+
const baseUrl = `https://${domain}`;
|
|
2552
|
+
const signalFor = () => options.signal ?? AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
2553
|
+
const robotsRes = await fetch(`${baseUrl}/robots.txt`, {
|
|
2554
|
+
headers: { "User-Agent": userAgent },
|
|
2555
|
+
signal: signalFor()
|
|
2556
|
+
}).catch(() => null);
|
|
2557
|
+
if (robotsRes?.ok) {
|
|
2558
|
+
const match = (await robotsRes.text()).match(SITEMAP_DIRECTIVE_RE);
|
|
2559
|
+
if (match?.[1]) {
|
|
2560
|
+
if ((await fetch(match[1], {
|
|
2561
|
+
method: "HEAD",
|
|
2562
|
+
signal: signalFor()
|
|
2563
|
+
}).catch(() => null))?.ok) return match[1];
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
for (const path of COMMON_PATHS) {
|
|
2567
|
+
const url = `${baseUrl}${path}`;
|
|
2568
|
+
if ((await fetch(url, {
|
|
2569
|
+
method: "HEAD",
|
|
2570
|
+
headers: { "User-Agent": userAgent },
|
|
2571
|
+
signal: signalFor()
|
|
2572
|
+
}).catch(() => null))?.ok) return url;
|
|
2573
|
+
}
|
|
2574
|
+
return null;
|
|
2575
|
+
}
|
|
2576
|
+
const LOC_RE = /<loc>([^<]+)<\/loc>/gi;
|
|
2577
|
+
const SITEMAPINDEX_RE = /<sitemapindex\b/i;
|
|
2578
|
+
async function fetchSitemapUrls(sitemapUrl, options = {}) {
|
|
2579
|
+
const userAgent = options.userAgent ?? "gscdump sitemap fetcher";
|
|
2580
|
+
const maxDepth = options.maxDepth ?? 3;
|
|
2581
|
+
const limit = options.limit;
|
|
2582
|
+
const signalFor = () => options.signal ?? AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
2583
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2584
|
+
const out = [];
|
|
2585
|
+
const visit = async (url, depth) => {
|
|
2586
|
+
if (limit != null && out.length >= limit) return;
|
|
2587
|
+
if (depth > maxDepth) return;
|
|
2588
|
+
const res = await fetch(url, {
|
|
2589
|
+
headers: { "User-Agent": userAgent },
|
|
2590
|
+
signal: signalFor()
|
|
2591
|
+
});
|
|
2592
|
+
if (!res.ok) throw new Error(`Fetch ${url} failed: ${res.status}`);
|
|
2593
|
+
const text = await res.text();
|
|
2594
|
+
const isIndex = SITEMAPINDEX_RE.test(text);
|
|
2595
|
+
const matches = [...text.matchAll(LOC_RE)].map((m) => m[1].trim()).filter(Boolean);
|
|
2596
|
+
if (isIndex) {
|
|
2597
|
+
for (const child of matches) {
|
|
2598
|
+
if (limit != null && out.length >= limit) return;
|
|
2599
|
+
await visit(child, depth + 1);
|
|
2600
|
+
}
|
|
2601
|
+
return;
|
|
2602
|
+
}
|
|
2603
|
+
for (const u of matches) {
|
|
2604
|
+
if (seen.has(u)) continue;
|
|
2605
|
+
seen.add(u);
|
|
2606
|
+
out.push(u);
|
|
2607
|
+
if (limit != null && out.length >= limit) return;
|
|
2608
|
+
}
|
|
2609
|
+
};
|
|
2610
|
+
await visit(sitemapUrl, 0);
|
|
2611
|
+
return out;
|
|
2612
|
+
}
|
|
2613
|
+
function urlMatchKey(url) {
|
|
2614
|
+
const u = URL.parse(url);
|
|
2615
|
+
if (!u) return null;
|
|
2616
|
+
return [u.hostname.replace(/^www\./, ""), u.pathname.replace(/\/$/, "") || "/"].join("").toLowerCase();
|
|
2617
|
+
}
|
|
2618
|
+
async function runSequentialBatch(items, operation, options = {}) {
|
|
2619
|
+
const { delayMs = 0, concurrency = 1, onProgress } = options;
|
|
2620
|
+
const results = Array.from({ length: items.length });
|
|
2621
|
+
let completed = 0;
|
|
2622
|
+
if (concurrency <= 1) {
|
|
2623
|
+
for (let i = 0; i < items.length; i++) {
|
|
2624
|
+
const result = await operation(items[i], i);
|
|
2625
|
+
results[i] = result;
|
|
2626
|
+
onProgress?.(result, i, items.length);
|
|
2627
|
+
if (i < items.length - 1 && delayMs > 0) await new Promise((r) => setTimeout(r, delayMs));
|
|
2628
|
+
}
|
|
2629
|
+
return results;
|
|
2630
|
+
}
|
|
2631
|
+
const cursor = { i: 0 };
|
|
2632
|
+
const worker = async () => {
|
|
2633
|
+
while (true) {
|
|
2634
|
+
const i = cursor.i++;
|
|
2635
|
+
if (i >= items.length) return;
|
|
2636
|
+
const result = await operation(items[i], i);
|
|
2637
|
+
results[i] = result;
|
|
2638
|
+
completed++;
|
|
2639
|
+
onProgress?.(result, completed - 1, items.length);
|
|
2640
|
+
if (delayMs > 0) await new Promise((r) => setTimeout(r, delayMs));
|
|
2641
|
+
}
|
|
2642
|
+
};
|
|
2643
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker));
|
|
2644
|
+
return results;
|
|
2645
|
+
}
|
|
2646
|
+
async function requestIndexing(client, url, options = {}) {
|
|
2647
|
+
const { type = "URL_UPDATED" } = options;
|
|
2648
|
+
return client.indexing.publish(url, type).then((r) => ({
|
|
2649
|
+
url,
|
|
2650
|
+
type,
|
|
2651
|
+
notifyTime: r.urlNotificationMetadata?.latestUpdate?.notifyTime || void 0
|
|
2652
|
+
}));
|
|
2653
|
+
}
|
|
2654
|
+
async function getIndexingMetadata(client, url) {
|
|
2655
|
+
return client.indexing.getMetadata(url).then((r) => ({
|
|
2656
|
+
url,
|
|
2657
|
+
latestUpdate: r.latestUpdate || void 0,
|
|
2658
|
+
latestRemove: r.latestRemove || void 0
|
|
2659
|
+
}));
|
|
2660
|
+
}
|
|
2661
|
+
async function batchRequestIndexing(client, urls, options = {}) {
|
|
2662
|
+
const { type = "URL_UPDATED", delayMs = 100, concurrency, onProgress } = options;
|
|
2663
|
+
return runSequentialBatch(urls, (url) => requestIndexing(client, url, { type }), {
|
|
2664
|
+
delayMs,
|
|
2665
|
+
concurrency,
|
|
2666
|
+
onProgress
|
|
2667
|
+
});
|
|
2668
|
+
}
|
|
2669
|
+
async function inspectUrl(client, siteUrl, inspectionUrl) {
|
|
2670
|
+
const inspection = (await client.inspect(siteUrl, inspectionUrl)).inspectionResult;
|
|
2671
|
+
return {
|
|
2672
|
+
inspection,
|
|
2673
|
+
isIndexed: inspection?.indexStatusResult?.verdict === "PASS"
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
async function batchInspectUrls(client, siteUrl, urls, options = {}) {
|
|
2677
|
+
const { delayMs = 200, concurrency, onProgress } = options;
|
|
2678
|
+
return runSequentialBatch(urls, async (url) => {
|
|
2679
|
+
const { inspection, isIndexed } = await inspectUrl(client, siteUrl, url);
|
|
2680
|
+
return {
|
|
2681
|
+
url,
|
|
2682
|
+
inspection,
|
|
2683
|
+
isIndexed
|
|
2684
|
+
};
|
|
2685
|
+
}, {
|
|
2686
|
+
delayMs,
|
|
2687
|
+
concurrency,
|
|
2688
|
+
onProgress
|
|
2689
|
+
});
|
|
2690
|
+
}
|
|
2691
|
+
async function inspectUrlFlat(client, siteUrl, inspectionUrl) {
|
|
2692
|
+
const inspection = (await client.inspect(siteUrl, inspectionUrl)).inspectionResult;
|
|
2693
|
+
const index = inspection?.indexStatusResult;
|
|
2694
|
+
const mobile = inspection?.mobileUsabilityResult;
|
|
2695
|
+
const rich = inspection?.richResultsResult;
|
|
2696
|
+
const amp = inspection?.ampResult;
|
|
2697
|
+
return {
|
|
2698
|
+
url: inspectionUrl,
|
|
2699
|
+
verdict: index?.verdict ?? null,
|
|
2700
|
+
coverageState: index?.coverageState ?? null,
|
|
2701
|
+
indexingState: index?.indexingState ?? null,
|
|
2702
|
+
robotsTxtState: index?.robotsTxtState ?? null,
|
|
2703
|
+
pageFetchState: index?.pageFetchState ?? null,
|
|
2704
|
+
lastCrawlTime: index?.lastCrawlTime ?? null,
|
|
2705
|
+
crawlingUserAgent: index?.crawledAs ?? null,
|
|
2706
|
+
userCanonical: index?.userCanonical ?? null,
|
|
2707
|
+
googleCanonical: index?.googleCanonical ?? null,
|
|
2708
|
+
sitemaps: index?.sitemap?.length ? JSON.stringify(index.sitemap) : null,
|
|
2709
|
+
referringUrls: index?.referringUrls?.length ? JSON.stringify(index.referringUrls) : null,
|
|
2710
|
+
mobileVerdict: mobile?.verdict ?? null,
|
|
2711
|
+
mobileIssues: mobile?.issues?.length ? JSON.stringify(mobile.issues) : null,
|
|
2712
|
+
richResultsVerdict: rich?.verdict ?? null,
|
|
2713
|
+
richResultsItems: rich?.detectedItems?.length ? JSON.stringify(rich.detectedItems) : null,
|
|
2714
|
+
ampVerdict: amp?.verdict ?? null,
|
|
2715
|
+
ampUrl: amp?.ampUrl ?? null,
|
|
2716
|
+
ampIndexingState: amp?.indexingState ?? null,
|
|
2717
|
+
ampIndexStatusVerdict: amp?.ampIndexStatusVerdict ?? null,
|
|
2718
|
+
ampRobotsTxtState: amp?.robotsTxtState ?? null,
|
|
2719
|
+
ampPageFetchState: amp?.pageFetchState ?? null,
|
|
2720
|
+
ampLastCrawlTime: amp?.lastCrawlTime ?? null,
|
|
2721
|
+
ampIssues: amp?.issues?.length ? JSON.stringify(amp.issues) : null,
|
|
2722
|
+
inspectionResultLink: inspection?.inspectionResultLink ?? null
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
function getNextCheckPriority(result) {
|
|
2726
|
+
if (!result.verdict || result.verdict === "VERDICT_UNSPECIFIED") return "medium";
|
|
2727
|
+
if (result.verdict === "FAIL" || result.verdict === "PARTIAL" || result.verdict === "NEUTRAL") return "high";
|
|
2728
|
+
if (result.verdict === "PASS") return "low";
|
|
2729
|
+
return "medium";
|
|
2730
|
+
}
|
|
2731
|
+
function getNextCheckAfter(priority) {
|
|
2732
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2733
|
+
switch (priority) {
|
|
2734
|
+
case "high": return now + 7 * 86400;
|
|
2735
|
+
case "medium": return now + 14 * 86400;
|
|
2736
|
+
case "low": return now + 30 * 86400;
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
const INSPECTION_ALLOWED_PERMISSIONS = new Set([
|
|
2740
|
+
"siteOwner",
|
|
2741
|
+
"siteFullUser",
|
|
2742
|
+
"siteRestrictedUser"
|
|
2743
|
+
]);
|
|
2744
|
+
function canUseUrlInspection(permissionLevel) {
|
|
2745
|
+
return !!permissionLevel && INSPECTION_ALLOWED_PERMISSIONS.has(permissionLevel);
|
|
2746
|
+
}
|
|
2747
|
+
function grantedScopeList(scopes) {
|
|
2748
|
+
return scopes?.split(/\s+/).map((s) => s.trim()).filter(Boolean) ?? [];
|
|
2749
|
+
}
|
|
2750
|
+
function getIndexingEligibility(grantedScopes, permissionLevel) {
|
|
2751
|
+
const scopes = grantedScopeList(grantedScopes);
|
|
2752
|
+
if (!hasIndexingScope(grantedScopes)) return {
|
|
2753
|
+
indexingEligible: false,
|
|
2754
|
+
indexingIneligibleReason: "missing_indexing_scope",
|
|
2755
|
+
indexingPermissionLevel: permissionLevel ?? null,
|
|
2756
|
+
grantedScopes: scopes
|
|
2757
|
+
};
|
|
2758
|
+
if (!canUseUrlInspection(permissionLevel)) return {
|
|
2759
|
+
indexingEligible: false,
|
|
2760
|
+
indexingIneligibleReason: "insufficient_gsc_permission",
|
|
2761
|
+
indexingPermissionLevel: permissionLevel ?? null,
|
|
2762
|
+
grantedScopes: scopes
|
|
2763
|
+
};
|
|
2764
|
+
return {
|
|
2765
|
+
indexingEligible: true,
|
|
2766
|
+
indexingPermissionLevel: permissionLevel ?? null,
|
|
2767
|
+
grantedScopes: scopes
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2770
|
+
const OAUTH_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
2771
|
+
const OAUTH_TIMEOUT_MS = 8e3;
|
|
2772
|
+
const OAUTH_MAX_ATTEMPTS = 3;
|
|
2773
|
+
const OAUTH_BACKOFF_MS = [
|
|
2774
|
+
0,
|
|
2775
|
+
400,
|
|
2776
|
+
1500
|
|
2777
|
+
];
|
|
2778
|
+
async function refreshAccessTokenResult(refreshToken, clientId, clientSecret) {
|
|
2779
|
+
return postOAuthTokenResult(new URLSearchParams({
|
|
2780
|
+
client_id: clientId,
|
|
2781
|
+
client_secret: clientSecret,
|
|
2782
|
+
refresh_token: refreshToken,
|
|
2783
|
+
grant_type: "refresh_token"
|
|
2784
|
+
}), "refresh");
|
|
2785
|
+
}
|
|
2786
|
+
async function refreshAccessToken(refreshToken, clientId, clientSecret) {
|
|
2787
|
+
return unwrapResult(await refreshAccessTokenResult(refreshToken, clientId, clientSecret), oauthErrorToException);
|
|
2788
|
+
}
|
|
2789
|
+
async function exchangeAuthCodeResult(code, clientId, clientSecret, redirectUri) {
|
|
2790
|
+
const result = await postOAuthTokenResult(new URLSearchParams({
|
|
2791
|
+
client_id: clientId,
|
|
2792
|
+
client_secret: clientSecret,
|
|
2793
|
+
code,
|
|
2794
|
+
redirect_uri: redirectUri,
|
|
2795
|
+
grant_type: "authorization_code"
|
|
2796
|
+
}), "exchange");
|
|
2797
|
+
if (!result.ok) return result;
|
|
2798
|
+
const refreshToken = result.value.refresh_token;
|
|
2799
|
+
return ok({
|
|
2800
|
+
...result.value,
|
|
2801
|
+
refreshToken
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
async function exchangeAuthCode(code, clientId, clientSecret, redirectUri) {
|
|
2805
|
+
return unwrapResult(await exchangeAuthCodeResult(code, clientId, clientSecret, redirectUri), oauthErrorToException);
|
|
2806
|
+
}
|
|
2807
|
+
function oauthHttpError(op, info) {
|
|
2808
|
+
const message = `Failed to ${op} token: ${info.message}`;
|
|
2809
|
+
const cause = new GscApiError(message, info);
|
|
2810
|
+
return info.reason === "invalid_grant" || info.code === 400 || info.code === 401 || info.code === 403 ? {
|
|
2811
|
+
kind: "auth-expired",
|
|
2812
|
+
message,
|
|
2813
|
+
cause
|
|
2814
|
+
} : {
|
|
2815
|
+
kind: "transport",
|
|
2816
|
+
message,
|
|
2817
|
+
status: info.code,
|
|
2818
|
+
cause
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2821
|
+
function oauthErrorToException(error) {
|
|
2822
|
+
return error.cause instanceof Error ? error.cause : gscErrorToException(error);
|
|
2823
|
+
}
|
|
2824
|
+
async function postOAuthTokenResult(body, op) {
|
|
2825
|
+
let lastError;
|
|
2826
|
+
for (let attempt = 0; attempt < OAUTH_MAX_ATTEMPTS; attempt++) {
|
|
2827
|
+
if (OAUTH_BACKOFF_MS[attempt]) await new Promise((r) => setTimeout(r, OAUTH_BACKOFF_MS[attempt]));
|
|
2828
|
+
const res = await fetch(OAUTH_TOKEN_URL, {
|
|
2829
|
+
method: "POST",
|
|
2830
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2831
|
+
body,
|
|
2832
|
+
signal: AbortSignal.timeout(OAUTH_TIMEOUT_MS)
|
|
2833
|
+
}).catch((error) => {
|
|
2834
|
+
lastError = error;
|
|
2835
|
+
return null;
|
|
2836
|
+
});
|
|
2837
|
+
if (!res) continue;
|
|
2838
|
+
if (!res.ok) return err(oauthHttpError(op, parseGoogleError(await res.text(), res.status)));
|
|
2839
|
+
const data = await res.json();
|
|
2840
|
+
return ok({
|
|
2841
|
+
accessToken: data.access_token,
|
|
2842
|
+
expiresAt: Math.floor(Date.now() / 1e3) + data.expires_in,
|
|
2843
|
+
refresh_token: data.refresh_token
|
|
2844
|
+
});
|
|
2845
|
+
}
|
|
2846
|
+
return err({
|
|
2847
|
+
kind: "transport",
|
|
2848
|
+
message: lastError instanceof Error ? lastError.message : `OAuth ${op} failed after ${OAUTH_MAX_ATTEMPTS} attempts`,
|
|
2849
|
+
cause: lastError
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
async function fetchSites(client) {
|
|
2853
|
+
return client.sites();
|
|
2854
|
+
}
|
|
2855
|
+
async function fetchSitesWithSitemaps(client) {
|
|
2856
|
+
const sites = (await client.sites()).filter((s) => !!s.siteUrl && s.permissionLevel !== "siteUnverifiedUser");
|
|
2857
|
+
return Promise.all(sites.map(async (site) => {
|
|
2858
|
+
const sitemaps = await client.sitemaps.list(site.siteUrl).catch(() => []);
|
|
2859
|
+
return {
|
|
2860
|
+
...site,
|
|
2861
|
+
sitemaps
|
|
2862
|
+
};
|
|
2863
|
+
}));
|
|
2864
|
+
}
|
|
2865
|
+
async function fetchSitemaps(client, siteUrl) {
|
|
2866
|
+
return client.sitemaps.list(siteUrl);
|
|
2867
|
+
}
|
|
2868
|
+
async function fetchSitemap(client, siteUrl, feedpath) {
|
|
2869
|
+
return client.sitemaps.get(siteUrl, feedpath);
|
|
2870
|
+
}
|
|
2871
|
+
async function submitSitemap(client, siteUrl, feedpath) {
|
|
2872
|
+
return client.sitemaps.submit(siteUrl, feedpath);
|
|
2873
|
+
}
|
|
2874
|
+
async function deleteSitemap(client, siteUrl, feedpath) {
|
|
2875
|
+
return client.sitemaps.delete(siteUrl, feedpath);
|
|
2876
|
+
}
|
|
2877
|
+
async function addSite(client, siteUrl) {
|
|
2878
|
+
return client.sites.add(siteUrl);
|
|
2879
|
+
}
|
|
2880
|
+
async function deleteSite(client, siteUrl) {
|
|
2881
|
+
return client.sites.delete(siteUrl);
|
|
2882
|
+
}
|
|
2883
|
+
const SC_DOMAIN_PREFIX = "sc-domain:";
|
|
2884
|
+
function siteUrlToVerificationSite(siteUrl) {
|
|
2885
|
+
if (siteUrl.startsWith(SC_DOMAIN_PREFIX)) return {
|
|
2886
|
+
type: "INET_DOMAIN",
|
|
2887
|
+
identifier: siteUrl.slice(10)
|
|
2888
|
+
};
|
|
2889
|
+
return {
|
|
2890
|
+
type: "SITE",
|
|
2891
|
+
identifier: siteUrl
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
function verificationMethodsFor(site) {
|
|
2895
|
+
if (site.type === "INET_DOMAIN") return ["DNS_TXT", "DNS_CNAME"];
|
|
2896
|
+
return [
|
|
2897
|
+
"META",
|
|
2898
|
+
"FILE",
|
|
2899
|
+
"ANALYTICS",
|
|
2900
|
+
"TAG_MANAGER"
|
|
2901
|
+
];
|
|
2902
|
+
}
|
|
2903
|
+
async function getVerificationToken(client, siteUrl, method) {
|
|
2904
|
+
const site = siteUrlToVerificationSite(siteUrl);
|
|
2905
|
+
return {
|
|
2906
|
+
...await client.verification.getToken({
|
|
2907
|
+
site,
|
|
2908
|
+
verificationMethod: method
|
|
2909
|
+
}),
|
|
2910
|
+
site
|
|
2911
|
+
};
|
|
2912
|
+
}
|
|
2913
|
+
async function verifySite(client, siteUrl, method) {
|
|
2914
|
+
const site = siteUrlToVerificationSite(siteUrl);
|
|
2915
|
+
return client.verification.insert({
|
|
2916
|
+
site,
|
|
2917
|
+
verificationMethod: method
|
|
2918
|
+
});
|
|
2919
|
+
}
|
|
2920
|
+
async function listVerifiedSites(client) {
|
|
2921
|
+
return client.verification.list();
|
|
2922
|
+
}
|
|
2923
|
+
async function getVerifiedSite(client, id) {
|
|
2924
|
+
return client.verification.get(id);
|
|
2925
|
+
}
|
|
2926
|
+
async function unverifySite(client, id) {
|
|
2927
|
+
return client.verification.delete(id);
|
|
2928
|
+
}
|
|
2929
|
+
export { GSC_QUOTAS, GscApiError, URL_INSPECTION_DAILY_LIMIT, URL_INSPECTION_EFFECTIVE_LIMIT, addSite, batchInspectUrls, batchRequestIndexing, canUseUrlInspection, classifyError, createAuth, createFetch, deleteSite, deleteSitemap, discoverSitemap, exchangeAuthCode, exchangeAuthCodeResult, fetchSitemap, fetchSitemapUrls, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatErrorForCli, formatGscPropertyCandidates, getIndexingEligibility, getIndexingMetadata, getNextCheckAfter, getNextCheckPriority, getVerificationToken, getVerifiedSite, googleSearchConsole, grantedScopeList, gscErrorToException, gscPropertyMatchesTarget, gscdumpApi, hasGscReadScope, hasGscWriteScope, hasIndexingScope, inspectUrl, inspectUrlFlat, isPermissionDeniedError, isVerifiedGscPermission, isVerifiedGscProperty, listVerifiedSites, matchGscSite, normalizeGscSiteUrl, normalizeRegistrationTarget, parseGoogleError, parseGscSiteUrl, pickBestGscProperty, refreshAccessToken, refreshAccessTokenResult, requestIndexing, rethrowAsGscApiError, runSequentialBatch, siteUrlToVerificationSite, storageError, submitSitemap, unverifySite, urlMatchKey, verificationMethodsFor, verifySite };
|