@agentsean/google 1.0.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/LICENSE +661 -0
- package/dist/audit-extras.d.ts +21 -0
- package/dist/audit-extras.d.ts.map +1 -0
- package/dist/audit-extras.js +62 -0
- package/dist/audit-extras.js.map +1 -0
- package/dist/broker.d.ts +47 -0
- package/dist/broker.d.ts.map +1 -0
- package/dist/broker.js +146 -0
- package/dist/broker.js.map +1 -0
- package/dist/causes.d.ts +157 -0
- package/dist/causes.d.ts.map +1 -0
- package/dist/causes.js +175 -0
- package/dist/causes.js.map +1 -0
- package/dist/connect-flow.d.ts +63 -0
- package/dist/connect-flow.d.ts.map +1 -0
- package/dist/connect-flow.js +150 -0
- package/dist/connect-flow.js.map +1 -0
- package/dist/crux.d.ts +37 -0
- package/dist/crux.d.ts.map +1 -0
- package/dist/crux.js +112 -0
- package/dist/crux.js.map +1 -0
- package/dist/data/changepoints.json +174 -0
- package/dist/data/quotas.json +17 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +110 -0
- package/dist/errors.js.map +1 -0
- package/dist/ga4.d.ts +46 -0
- package/dist/ga4.d.ts.map +1 -0
- package/dist/ga4.js +126 -0
- package/dist/ga4.js.map +1 -0
- package/dist/gsc.d.ts +98 -0
- package/dist/gsc.d.ts.map +1 -0
- package/dist/gsc.js +141 -0
- package/dist/gsc.js.map +1 -0
- package/dist/http.d.ts +14 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +47 -0
- package/dist/http.js.map +1 -0
- package/dist/incidents.d.ts +51 -0
- package/dist/incidents.d.ts.map +1 -0
- package/dist/incidents.js +221 -0
- package/dist/incidents.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/integrity.d.ts +32 -0
- package/dist/integrity.d.ts.map +1 -0
- package/dist/integrity.js +52 -0
- package/dist/integrity.js.map +1 -0
- package/dist/oauth-broker.d.ts +38 -0
- package/dist/oauth-broker.d.ts.map +1 -0
- package/dist/oauth-broker.js +81 -0
- package/dist/oauth-broker.js.map +1 -0
- package/dist/oauth-config.d.ts +16 -0
- package/dist/oauth-config.d.ts.map +1 -0
- package/dist/oauth-config.js +24 -0
- package/dist/oauth-config.js.map +1 -0
- package/dist/oauth-desktop.d.ts +29 -0
- package/dist/oauth-desktop.d.ts.map +1 -0
- package/dist/oauth-desktop.js +76 -0
- package/dist/oauth-desktop.js.map +1 -0
- package/dist/pending.d.ts +18 -0
- package/dist/pending.d.ts.map +1 -0
- package/dist/pending.js +29 -0
- package/dist/pending.js.map +1 -0
- package/dist/persist.d.ts +48 -0
- package/dist/persist.d.ts.map +1 -0
- package/dist/persist.js +298 -0
- package/dist/persist.js.map +1 -0
- package/dist/pkce.d.ts +9 -0
- package/dist/pkce.d.ts.map +1 -0
- package/dist/pkce.js +13 -0
- package/dist/pkce.js.map +1 -0
- package/dist/psi.d.ts +19 -0
- package/dist/psi.d.ts.map +1 -0
- package/dist/psi.js +47 -0
- package/dist/psi.js.map +1 -0
- package/dist/quota.d.ts +22 -0
- package/dist/quota.d.ts.map +1 -0
- package/dist/quota.js +136 -0
- package/dist/quota.js.map +1 -0
- package/dist/reconcile.d.ts +19 -0
- package/dist/reconcile.d.ts.map +1 -0
- package/dist/reconcile.js +89 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/scopes.d.ts +25 -0
- package/dist/scopes.d.ts.map +1 -0
- package/dist/scopes.js +49 -0
- package/dist/scopes.js.map +1 -0
- package/dist/seal.d.ts +4 -0
- package/dist/seal.d.ts.map +1 -0
- package/dist/seal.js +27 -0
- package/dist/seal.js.map +1 -0
- package/dist/sync.d.ts +29 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +266 -0
- package/dist/sync.js.map +1 -0
- package/dist/tokens.d.ts +57 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +122 -0
- package/dist/tokens.js.map +1 -0
- package/dist/verification.d.ts +17 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +51 -0
- package/dist/verification.js.map +1 -0
- package/dist/waterfall.d.ts +39 -0
- package/dist/waterfall.d.ts.map +1 -0
- package/dist/waterfall.js +167 -0
- package/dist/waterfall.js.map +1 -0
- package/package.json +52 -0
package/dist/errors.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapted from OpenSEO `src/server/lib/gscErrors.ts` and `ga4Errors.ts` (MIT).
|
|
3
|
+
* Copyright (c) 2026 Ben Senescu and contributors.
|
|
4
|
+
*
|
|
5
|
+
* Workers/Better-Auth bindings stripped. Status-driven user-facing messages kept.
|
|
6
|
+
*/
|
|
7
|
+
export class GscApiError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
body;
|
|
10
|
+
constructor(status, message, body) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.body = body;
|
|
14
|
+
this.name = "GscApiError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class GscTokenError extends Error {
|
|
18
|
+
cause;
|
|
19
|
+
constructor(message, cause) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.cause = cause;
|
|
22
|
+
this.name = "GscTokenError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class GscNotConnectedError extends Error {
|
|
26
|
+
siteId;
|
|
27
|
+
constructor(siteId) {
|
|
28
|
+
super("Search Console is not connected for this site");
|
|
29
|
+
this.siteId = siteId;
|
|
30
|
+
this.name = "GscNotConnectedError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class Ga4AdminApiError extends Error {
|
|
34
|
+
status;
|
|
35
|
+
constructor(status, message) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.status = status;
|
|
38
|
+
this.name = "Ga4AdminApiError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class Ga4TokenError extends Error {
|
|
42
|
+
cause;
|
|
43
|
+
constructor(message, cause) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.cause = cause;
|
|
46
|
+
this.name = "Ga4TokenError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export class Ga4DataApiError extends Error {
|
|
50
|
+
status;
|
|
51
|
+
retryAfterSeconds;
|
|
52
|
+
upstreamReason;
|
|
53
|
+
constructor(status, message, retryAfterSeconds = null, upstreamReason = null) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.status = status;
|
|
56
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
57
|
+
this.upstreamReason = upstreamReason;
|
|
58
|
+
this.name = "Ga4DataApiError";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export class Ga4NotConnectedError extends Error {
|
|
62
|
+
siteId;
|
|
63
|
+
constructor(siteId) {
|
|
64
|
+
super("Google Analytics is not connected for this site");
|
|
65
|
+
this.siteId = siteId;
|
|
66
|
+
this.name = "Ga4NotConnectedError";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export class QuotaExceededError extends Error {
|
|
70
|
+
api;
|
|
71
|
+
retryAfterMs;
|
|
72
|
+
constructor(api, message, retryAfterMs) {
|
|
73
|
+
super(message);
|
|
74
|
+
this.api = api;
|
|
75
|
+
this.retryAfterMs = retryAfterMs;
|
|
76
|
+
this.name = "QuotaExceededError";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function gscMessageForStatus(status, body) {
|
|
80
|
+
if (status === 401 || status === 403) {
|
|
81
|
+
return "Search Console denied access to this property (no verified permission, or the connection was revoked).";
|
|
82
|
+
}
|
|
83
|
+
if (status === 429) {
|
|
84
|
+
return "Search Console rate limit reached. Retry shortly.";
|
|
85
|
+
}
|
|
86
|
+
if (status === 404) {
|
|
87
|
+
return "Search Console property not found. It may have been removed in Search Console.";
|
|
88
|
+
}
|
|
89
|
+
return `Search Console API error (${status}): ${body.slice(0, 300)}`;
|
|
90
|
+
}
|
|
91
|
+
export function ga4AdminMessageForStatus(status) {
|
|
92
|
+
if (status === 401)
|
|
93
|
+
return "Google Analytics connection expired.";
|
|
94
|
+
if (status === 403) {
|
|
95
|
+
return "Google Analytics denied access. Check the account's property access and enabled APIs.";
|
|
96
|
+
}
|
|
97
|
+
if (status === 429)
|
|
98
|
+
return "Google Analytics rate limit reached.";
|
|
99
|
+
return `Google Analytics Admin API error (${status}).`;
|
|
100
|
+
}
|
|
101
|
+
export function ga4DataMessageForStatus(status) {
|
|
102
|
+
if (status === 401)
|
|
103
|
+
return "Google Analytics connection expired.";
|
|
104
|
+
if (status === 403)
|
|
105
|
+
return "Google Analytics Data API denied access.";
|
|
106
|
+
if (status === 429)
|
|
107
|
+
return "Google Analytics Data API quota exhausted.";
|
|
108
|
+
return `Google Analytics Data API error (${status}).`;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/ga4.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapted from OpenSEO `src/server/lib/ga4Client.ts` and `ga4Errors.ts` (MIT).
|
|
3
|
+
* Copyright (c) 2026 Ben Senescu and contributors.
|
|
4
|
+
*
|
|
5
|
+
* Sparse-response handling kept: ProtoJSON omits default scalars. Workers
|
|
6
|
+
* bindings and Better Auth token minting stripped.
|
|
7
|
+
*/
|
|
8
|
+
import { type GoogleHttp } from "./http.js";
|
|
9
|
+
export type Ga4PropertySummary = {
|
|
10
|
+
propertyId: string;
|
|
11
|
+
displayName: string;
|
|
12
|
+
accountId: string;
|
|
13
|
+
accountDisplayName: string;
|
|
14
|
+
};
|
|
15
|
+
export type Ga4Property = {
|
|
16
|
+
name: string;
|
|
17
|
+
displayName: string;
|
|
18
|
+
timeZone: string;
|
|
19
|
+
currencyCode: string;
|
|
20
|
+
};
|
|
21
|
+
export type Ga4ReportRow = {
|
|
22
|
+
dimensionValues: string[];
|
|
23
|
+
metricValues: number[];
|
|
24
|
+
};
|
|
25
|
+
export type Ga4Client = {
|
|
26
|
+
listProperties: () => Promise<Ga4PropertySummary[]>;
|
|
27
|
+
getProperty: (propertyId: string) => Promise<Ga4Property>;
|
|
28
|
+
runReport: (opts: {
|
|
29
|
+
propertyId: string;
|
|
30
|
+
startDate: string;
|
|
31
|
+
endDate: string;
|
|
32
|
+
dimensions: string[];
|
|
33
|
+
metrics: string[];
|
|
34
|
+
dimensionFilter?: unknown;
|
|
35
|
+
limit?: number | undefined;
|
|
36
|
+
}) => Promise<{
|
|
37
|
+
rows: Ga4ReportRow[];
|
|
38
|
+
tokensConsumed: number;
|
|
39
|
+
}>;
|
|
40
|
+
};
|
|
41
|
+
export declare function createGa4Client(opts: {
|
|
42
|
+
http: GoogleHttp;
|
|
43
|
+
getToken: () => Promise<string>;
|
|
44
|
+
}): Ga4Client;
|
|
45
|
+
export declare function googleOrganicFilter(): unknown;
|
|
46
|
+
//# sourceMappingURL=ga4.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ga4.d.ts","sourceRoot":"","sources":["../src/ga4.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAKjE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,cAAc,EAAE,MAAM,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACpD,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1D,SAAS,EAAE,CAAC,IAAI,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE,CAAC;AAWF,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACjC,GAAG,SAAS,CA0HZ;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAmB7C"}
|
package/dist/ga4.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapted from OpenSEO `src/server/lib/ga4Client.ts` and `ga4Errors.ts` (MIT).
|
|
3
|
+
* Copyright (c) 2026 Ben Senescu and contributors.
|
|
4
|
+
*
|
|
5
|
+
* Sparse-response handling kept: ProtoJSON omits default scalars. Workers
|
|
6
|
+
* bindings and Better Auth token minting stripped.
|
|
7
|
+
*/
|
|
8
|
+
import { Ga4AdminApiError, Ga4DataApiError, ga4AdminMessageForStatus, ga4DataMessageForStatus, } from "./errors.js";
|
|
9
|
+
import { bearer, googleFetch } from "./http.js";
|
|
10
|
+
const GA4_ADMIN = "https://analyticsadmin.googleapis.com/v1beta";
|
|
11
|
+
const GA4_DATA = "https://analyticsdata.googleapis.com/v1beta";
|
|
12
|
+
function num(value) {
|
|
13
|
+
if (typeof value === "number")
|
|
14
|
+
return value;
|
|
15
|
+
if (typeof value === "string")
|
|
16
|
+
return Number(value) || 0;
|
|
17
|
+
if (value && typeof value === "object" && "value" in value) {
|
|
18
|
+
return Number(value.value) || 0;
|
|
19
|
+
}
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
export function createGa4Client(opts) {
|
|
23
|
+
const adminGet = async (path) => {
|
|
24
|
+
const token = await opts.getToken();
|
|
25
|
+
const res = await googleFetch(opts.http, "ga4.data", "admin", `${GA4_ADMIN}/${path}`, {
|
|
26
|
+
headers: bearer(token),
|
|
27
|
+
});
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
throw new Ga4AdminApiError(res.status, ga4AdminMessageForStatus(res.status));
|
|
30
|
+
}
|
|
31
|
+
return (await res.json());
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
async listProperties() {
|
|
35
|
+
const out = [];
|
|
36
|
+
let pageToken;
|
|
37
|
+
for (let i = 0; i < 100; i++) {
|
|
38
|
+
const q = pageToken ? `?pageToken=${encodeURIComponent(pageToken)}` : "";
|
|
39
|
+
const data = await adminGet(`accountSummaries${q}`);
|
|
40
|
+
for (const acc of data.accountSummaries ?? []) {
|
|
41
|
+
for (const p of acc.propertySummaries ?? []) {
|
|
42
|
+
if (!p.property)
|
|
43
|
+
continue;
|
|
44
|
+
out.push({
|
|
45
|
+
propertyId: p.property,
|
|
46
|
+
displayName: p.displayName ?? p.property,
|
|
47
|
+
accountId: acc.account ?? "",
|
|
48
|
+
accountDisplayName: acc.displayName ?? "",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
pageToken = data.nextPageToken;
|
|
53
|
+
if (!pageToken)
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
},
|
|
58
|
+
async getProperty(propertyId) {
|
|
59
|
+
const id = propertyId.startsWith("properties/")
|
|
60
|
+
? propertyId
|
|
61
|
+
: `properties/${propertyId}`;
|
|
62
|
+
const data = await adminGet(id);
|
|
63
|
+
return {
|
|
64
|
+
name: data.name ?? id,
|
|
65
|
+
displayName: data.displayName ?? id,
|
|
66
|
+
timeZone: data.timeZone ?? "UTC",
|
|
67
|
+
currencyCode: data.currencyCode ?? "USD",
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
async runReport(input) {
|
|
71
|
+
const token = await opts.getToken();
|
|
72
|
+
const id = input.propertyId.startsWith("properties/")
|
|
73
|
+
? input.propertyId
|
|
74
|
+
: `properties/${input.propertyId}`;
|
|
75
|
+
const body = {
|
|
76
|
+
dateRanges: [{ startDate: input.startDate, endDate: input.endDate }],
|
|
77
|
+
dimensions: input.dimensions.map((name) => ({ name })),
|
|
78
|
+
metrics: input.metrics.map((name) => ({ name })),
|
|
79
|
+
limit: String(input.limit ?? 10000),
|
|
80
|
+
...(input.dimensionFilter ? { dimensionFilter: input.dimensionFilter } : {}),
|
|
81
|
+
};
|
|
82
|
+
const res = await googleFetch(opts.http, "ga4.data", id, `${GA4_DATA}/${id}:runReport`, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: bearer(token, { "Content-Type": "application/json" }),
|
|
85
|
+
body: JSON.stringify(body),
|
|
86
|
+
});
|
|
87
|
+
if (!res.ok) {
|
|
88
|
+
const text = await res.text().catch(() => "");
|
|
89
|
+
let retryAfter = null;
|
|
90
|
+
const ra = res.headers.get("retry-after");
|
|
91
|
+
if (ra)
|
|
92
|
+
retryAfter = Number(ra) || null;
|
|
93
|
+
throw new Ga4DataApiError(res.status, ga4DataMessageForStatus(res.status), retryAfter, text.slice(0, 300));
|
|
94
|
+
}
|
|
95
|
+
const data = (await res.json());
|
|
96
|
+
// Sparse: omitted rows mean zero. Empty array is a valid sparse response.
|
|
97
|
+
const rows = (data.rows ?? []).map((r) => ({
|
|
98
|
+
dimensionValues: (r.dimensionValues ?? []).map((d) => d.value ?? ""),
|
|
99
|
+
metricValues: (r.metricValues ?? []).map((m) => num(m.value)),
|
|
100
|
+
}));
|
|
101
|
+
const tokensConsumed = data.propertyQuota?.tokensPerHour?.consumed ?? 1;
|
|
102
|
+
return { rows, tokensConsumed };
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export function googleOrganicFilter() {
|
|
107
|
+
return {
|
|
108
|
+
andGroup: {
|
|
109
|
+
expressions: [
|
|
110
|
+
{
|
|
111
|
+
filter: {
|
|
112
|
+
fieldName: "sessionSource",
|
|
113
|
+
stringFilter: { matchType: "EXACT", value: "google" },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
filter: {
|
|
118
|
+
fieldName: "sessionMedium",
|
|
119
|
+
stringFilter: { matchType: "EXACT", value: "organic" },
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=ga4.js.map
|
package/dist/ga4.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ga4.js","sourceRoot":"","sources":["../src/ga4.ts"],"names":[],"mappings":"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"}
|
package/dist/gsc.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapted from OpenSEO `src/server/lib/gscClient.ts` and
|
|
3
|
+
* `src/server/features/gsc/searchAnalytics.ts` (MIT).
|
|
4
|
+
* Copyright (c) 2026 Ben Senescu and contributors.
|
|
5
|
+
*
|
|
6
|
+
* Workers/Better-Auth bindings stripped. Pagination uses the real 25,000
|
|
7
|
+
* rowLimit (OpenSEO capped MCP at 1,000). siteUrl is used verbatim.
|
|
8
|
+
*/
|
|
9
|
+
import { type GoogleHttp } from "./http.js";
|
|
10
|
+
export declare const GSC_ROW_LIMIT_MAX = 25000;
|
|
11
|
+
export declare const GSC_ROWS_PER_DAY_PER_TYPE = 50000;
|
|
12
|
+
export declare const GSC_SEARCH_TYPES: readonly ["web", "image", "video", "news", "discover", "googleNews"];
|
|
13
|
+
export type GscSite = {
|
|
14
|
+
siteUrl: string;
|
|
15
|
+
permissionLevel: string;
|
|
16
|
+
};
|
|
17
|
+
export type GscSearchAnalyticsRow = {
|
|
18
|
+
keys?: string[] | undefined;
|
|
19
|
+
clicks: number;
|
|
20
|
+
impressions: number;
|
|
21
|
+
ctr: number;
|
|
22
|
+
position: number;
|
|
23
|
+
};
|
|
24
|
+
export type GscSearchAnalyticsRequest = {
|
|
25
|
+
startDate: string;
|
|
26
|
+
endDate: string;
|
|
27
|
+
dimensions?: string[] | undefined;
|
|
28
|
+
dimensionFilterGroups?: Array<{
|
|
29
|
+
groupType: "and" | "or";
|
|
30
|
+
filters: Array<{
|
|
31
|
+
dimension: string;
|
|
32
|
+
operator: string;
|
|
33
|
+
expression: string;
|
|
34
|
+
}>;
|
|
35
|
+
}> | undefined;
|
|
36
|
+
rowLimit?: number | undefined;
|
|
37
|
+
startRow?: number | undefined;
|
|
38
|
+
type?: string | undefined;
|
|
39
|
+
dataState?: string | undefined;
|
|
40
|
+
aggregationType?: string | undefined;
|
|
41
|
+
};
|
|
42
|
+
export type UrlInspectionResult = {
|
|
43
|
+
indexStatusResult?: {
|
|
44
|
+
verdict?: string;
|
|
45
|
+
coverageState?: string;
|
|
46
|
+
robotsTxtState?: string;
|
|
47
|
+
indexingState?: string;
|
|
48
|
+
lastCrawlTime?: string;
|
|
49
|
+
pageFetchState?: string;
|
|
50
|
+
googleCanonical?: string;
|
|
51
|
+
userCanonical?: string;
|
|
52
|
+
crawledAs?: string;
|
|
53
|
+
sitemap?: string[];
|
|
54
|
+
referringUrls?: string[];
|
|
55
|
+
};
|
|
56
|
+
mobileUsabilityResult?: {
|
|
57
|
+
verdict?: string;
|
|
58
|
+
};
|
|
59
|
+
richResultsResult?: {
|
|
60
|
+
verdict?: string;
|
|
61
|
+
};
|
|
62
|
+
inspectionResultLink?: string;
|
|
63
|
+
};
|
|
64
|
+
export type GscClient = {
|
|
65
|
+
listSites: () => Promise<GscSite[]>;
|
|
66
|
+
addSite: (siteUrl: string) => Promise<void>;
|
|
67
|
+
listSitemaps: (siteUrl: string) => Promise<unknown>;
|
|
68
|
+
submitSitemap: (siteUrl: string, feedpath: string) => Promise<void>;
|
|
69
|
+
deleteSitemap: (siteUrl: string, feedpath: string) => Promise<void>;
|
|
70
|
+
querySearchAnalytics: (siteUrl: string, body: GscSearchAnalyticsRequest) => Promise<{
|
|
71
|
+
rows: GscSearchAnalyticsRow[];
|
|
72
|
+
firstIncompleteDate: string | null;
|
|
73
|
+
}>;
|
|
74
|
+
querySearchAnalyticsAllPages: (siteUrl: string, body: Omit<GscSearchAnalyticsRequest, "startRow" | "rowLimit"> & {
|
|
75
|
+
rowLimit?: number | undefined;
|
|
76
|
+
}) => Promise<{
|
|
77
|
+
rows: GscSearchAnalyticsRow[];
|
|
78
|
+
firstIncompleteDate: string | null;
|
|
79
|
+
}>;
|
|
80
|
+
inspectUrl: (siteUrl: string, inspectionUrl: string, languageCode?: string | undefined) => Promise<UrlInspectionResult | null>;
|
|
81
|
+
};
|
|
82
|
+
export declare function createGscClient(opts: {
|
|
83
|
+
http: GoogleHttp;
|
|
84
|
+
getToken: () => Promise<string>;
|
|
85
|
+
}): GscClient;
|
|
86
|
+
export declare function ymd(d: Date): string;
|
|
87
|
+
export declare function subtractUtcDays(d: Date, days: number): Date;
|
|
88
|
+
export declare function subtractUtcMonths(date: Date, months: number): Date;
|
|
89
|
+
/** final data trails ~2–3 days. Never hardcode lag when metadata is present. */
|
|
90
|
+
export declare function defaultGscWindow(today?: Date): {
|
|
91
|
+
startDate: string;
|
|
92
|
+
endDate: string;
|
|
93
|
+
};
|
|
94
|
+
export declare function monthChunks(startDate: string, endDate: string): {
|
|
95
|
+
startDate: string;
|
|
96
|
+
endDate: string;
|
|
97
|
+
}[];
|
|
98
|
+
//# sourceMappingURL=gsc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gsc.d.ts","sourceRoot":"","sources":["../src/gsc.ts"],"names":[],"mappings":"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"}
|
package/dist/gsc.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapted from OpenSEO `src/server/lib/gscClient.ts` and
|
|
3
|
+
* `src/server/features/gsc/searchAnalytics.ts` (MIT).
|
|
4
|
+
* Copyright (c) 2026 Ben Senescu and contributors.
|
|
5
|
+
*
|
|
6
|
+
* Workers/Better-Auth bindings stripped. Pagination uses the real 25,000
|
|
7
|
+
* rowLimit (OpenSEO capped MCP at 1,000). siteUrl is used verbatim.
|
|
8
|
+
*/
|
|
9
|
+
import { encodeSiteUrl } from "./scopes.js";
|
|
10
|
+
import { GscApiError, gscMessageForStatus } from "./errors.js";
|
|
11
|
+
import { bearer, googleFetch } from "./http.js";
|
|
12
|
+
const GSC_API_BASE = "https://www.googleapis.com/webmasters/v3";
|
|
13
|
+
const INSPECT_URL = "https://searchconsole.googleapis.com/v1/urlInspection/index:inspect";
|
|
14
|
+
export const GSC_ROW_LIMIT_MAX = 25_000;
|
|
15
|
+
export const GSC_ROWS_PER_DAY_PER_TYPE = 50_000;
|
|
16
|
+
export const GSC_SEARCH_TYPES = [
|
|
17
|
+
"web",
|
|
18
|
+
"image",
|
|
19
|
+
"video",
|
|
20
|
+
"news",
|
|
21
|
+
"discover",
|
|
22
|
+
"googleNews",
|
|
23
|
+
];
|
|
24
|
+
export function createGscClient(opts) {
|
|
25
|
+
const request = async (api, scopeKey, url, init) => {
|
|
26
|
+
const token = await opts.getToken();
|
|
27
|
+
const hasBody = init?.body !== undefined;
|
|
28
|
+
const res = await googleFetch(opts.http, api, scopeKey, url, {
|
|
29
|
+
method: init?.method ?? "GET",
|
|
30
|
+
headers: bearer(token, hasBody ? { "Content-Type": "application/json" } : undefined),
|
|
31
|
+
...(hasBody ? { body: JSON.stringify(init?.body) } : {}),
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
const body = await res.text().catch(() => "");
|
|
35
|
+
throw new GscApiError(res.status, gscMessageForStatus(res.status, body), body);
|
|
36
|
+
}
|
|
37
|
+
if (res.status === 204)
|
|
38
|
+
return undefined;
|
|
39
|
+
return (await res.json());
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
async listSites() {
|
|
43
|
+
const data = await request("gsc.other", "sites", `${GSC_API_BASE}/sites`);
|
|
44
|
+
return data.siteEntry ?? [];
|
|
45
|
+
},
|
|
46
|
+
async addSite(siteUrl) {
|
|
47
|
+
await request("gsc.other", siteUrl, `${GSC_API_BASE}/sites/${encodeSiteUrl(siteUrl)}`, { method: "PUT", body: {} });
|
|
48
|
+
},
|
|
49
|
+
async listSitemaps(siteUrl) {
|
|
50
|
+
return request("gsc.other", siteUrl, `${GSC_API_BASE}/sites/${encodeSiteUrl(siteUrl)}/sitemaps`);
|
|
51
|
+
},
|
|
52
|
+
async submitSitemap(siteUrl, feedpath) {
|
|
53
|
+
await request("gsc.other", siteUrl, `${GSC_API_BASE}/sites/${encodeSiteUrl(siteUrl)}/sitemaps/${encodeURIComponent(feedpath)}`, { method: "PUT", body: {} });
|
|
54
|
+
},
|
|
55
|
+
async deleteSitemap(siteUrl, feedpath) {
|
|
56
|
+
await request("gsc.other", siteUrl, `${GSC_API_BASE}/sites/${encodeSiteUrl(siteUrl)}/sitemaps/${encodeURIComponent(feedpath)}`, { method: "DELETE" });
|
|
57
|
+
},
|
|
58
|
+
async querySearchAnalytics(siteUrl, body) {
|
|
59
|
+
const data = await request("gsc.searchAnalytics", siteUrl, `${GSC_API_BASE}/sites/${encodeSiteUrl(siteUrl)}/searchAnalytics/query`, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: {
|
|
62
|
+
...body,
|
|
63
|
+
rowLimit: Math.min(body.rowLimit ?? GSC_ROW_LIMIT_MAX, GSC_ROW_LIMIT_MAX),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
rows: data.rows ?? [],
|
|
68
|
+
firstIncompleteDate: data.metadata?.firstIncompleteDate ?? null,
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
async querySearchAnalyticsAllPages(siteUrl, body) {
|
|
72
|
+
const rowLimit = Math.min(body.rowLimit ?? GSC_ROW_LIMIT_MAX, GSC_ROW_LIMIT_MAX);
|
|
73
|
+
const rows = [];
|
|
74
|
+
let startRow = 0;
|
|
75
|
+
let firstIncompleteDate = null;
|
|
76
|
+
for (;;) {
|
|
77
|
+
const page = await this.querySearchAnalytics(siteUrl, {
|
|
78
|
+
...body,
|
|
79
|
+
rowLimit,
|
|
80
|
+
startRow,
|
|
81
|
+
});
|
|
82
|
+
if (page.firstIncompleteDate)
|
|
83
|
+
firstIncompleteDate = page.firstIncompleteDate;
|
|
84
|
+
rows.push(...page.rows);
|
|
85
|
+
if (page.rows.length < rowLimit)
|
|
86
|
+
break;
|
|
87
|
+
startRow += page.rows.length;
|
|
88
|
+
if (startRow >= GSC_ROWS_PER_DAY_PER_TYPE)
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
return { rows, firstIncompleteDate };
|
|
92
|
+
},
|
|
93
|
+
async inspectUrl(siteUrl, inspectionUrl, languageCode) {
|
|
94
|
+
const data = await request("gsc.urlInspection", siteUrl, INSPECT_URL, {
|
|
95
|
+
method: "POST",
|
|
96
|
+
body: {
|
|
97
|
+
siteUrl,
|
|
98
|
+
inspectionUrl,
|
|
99
|
+
...(languageCode ? { languageCode } : {}),
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
return data.inspectionResult ?? null;
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export function ymd(d) {
|
|
107
|
+
return d.toISOString().slice(0, 10);
|
|
108
|
+
}
|
|
109
|
+
export function subtractUtcDays(d, days) {
|
|
110
|
+
const n = new Date(d);
|
|
111
|
+
n.setUTCDate(n.getUTCDate() - days);
|
|
112
|
+
return n;
|
|
113
|
+
}
|
|
114
|
+
export function subtractUtcMonths(date, months) {
|
|
115
|
+
const day = date.getUTCDate();
|
|
116
|
+
const d = new Date(date);
|
|
117
|
+
d.setUTCDate(1);
|
|
118
|
+
d.setUTCMonth(d.getUTCMonth() - months);
|
|
119
|
+
const daysInTarget = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0)).getUTCDate();
|
|
120
|
+
d.setUTCDate(Math.min(day, daysInTarget));
|
|
121
|
+
return d;
|
|
122
|
+
}
|
|
123
|
+
/** final data trails ~2–3 days. Never hardcode lag when metadata is present. */
|
|
124
|
+
export function defaultGscWindow(today = new Date()) {
|
|
125
|
+
const end = subtractUtcDays(today, 3);
|
|
126
|
+
const start = subtractUtcMonths(end, 16);
|
|
127
|
+
return { startDate: ymd(start), endDate: ymd(end) };
|
|
128
|
+
}
|
|
129
|
+
export function monthChunks(startDate, endDate) {
|
|
130
|
+
const chunks = [];
|
|
131
|
+
let cursor = new Date(`${startDate}T00:00:00Z`);
|
|
132
|
+
const end = new Date(`${endDate}T00:00:00Z`);
|
|
133
|
+
while (cursor <= end) {
|
|
134
|
+
const monthEnd = new Date(Date.UTC(cursor.getUTCFullYear(), cursor.getUTCMonth() + 1, 0));
|
|
135
|
+
const sliceEnd = monthEnd < end ? monthEnd : end;
|
|
136
|
+
chunks.push({ startDate: ymd(cursor), endDate: ymd(sliceEnd) });
|
|
137
|
+
cursor = new Date(Date.UTC(sliceEnd.getUTCFullYear(), sliceEnd.getUTCMonth(), sliceEnd.getUTCDate() + 1));
|
|
138
|
+
}
|
|
139
|
+
return chunks;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=gsc.js.map
|
package/dist/gsc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gsc.js","sourceRoot":"","sources":["../src/gsc.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,WAAW,EAAmB,MAAM,WAAW,CAAC;AAEjE,MAAM,YAAY,GAAG,0CAA0C,CAAC;AAChE,MAAM,WAAW,GACf,qEAAqE,CAAC;AAExE,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACxC,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAChD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,KAAK;IACL,OAAO;IACP,OAAO;IACP,MAAM;IACN,UAAU;IACV,YAAY;CACJ,CAAC;AAgFX,MAAM,UAAU,eAAe,CAAC,IAG/B;IACC,MAAM,OAAO,GAAG,KAAK,EACnB,GAA8D,EAC9D,QAAgB,EAChB,GAAW,EACX,IAA0C,EAC9B,EAAE;QACd,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;YAC3D,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK;YAC7B,OAAO,EAAE,MAAM,CACb,KAAK,EACL,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,SAAS,CAC7D;YACD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAc,CAAC;QAC9C,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;IACjC,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,SAAS;YACb,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,WAAW,EACX,OAAO,EACP,GAAG,YAAY,QAAQ,CACxB,CAAC;YACF,OAAO,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;QAC9B,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,OAAO;YACnB,MAAM,OAAO,CACX,WAAW,EACX,OAAO,EACP,GAAG,YAAY,UAAU,aAAa,CAAC,OAAO,CAAC,EAAE,EACjD,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAC5B,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,OAAO;YACxB,OAAO,OAAO,CACZ,WAAW,EACX,OAAO,EACP,GAAG,YAAY,UAAU,aAAa,CAAC,OAAO,CAAC,WAAW,CAC3D,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ;YACnC,MAAM,OAAO,CACX,WAAW,EACX,OAAO,EACP,GAAG,YAAY,UAAU,aAAa,CAAC,OAAO,CAAC,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAC1F,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAC5B,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ;YACnC,MAAM,OAAO,CACX,WAAW,EACX,OAAO,EACP,GAAG,YAAY,UAAU,aAAa,CAAC,OAAO,CAAC,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAC1F,EAAE,MAAM,EAAE,QAAQ,EAAE,CACrB,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,oBAAoB,CAAC,OAAO,EAAE,IAAI;YACtC,MAAM,IAAI,GAAG,MAAM,OAAO,CAKxB,qBAAqB,EACrB,OAAO,EACP,GAAG,YAAY,UAAU,aAAa,CAAC,OAAO,CAAC,wBAAwB,EACvE;gBACE,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE;oBACJ,GAAG,IAAI;oBACP,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,iBAAiB,EAAE,iBAAiB,CAAC;iBAC1E;aACF,CACF,CAAC;YACF,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;gBACrB,mBAAmB,EAAE,IAAI,CAAC,QAAQ,EAAE,mBAAmB,IAAI,IAAI;aAChE,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,4BAA4B,CAAC,OAAO,EAAE,IAAI;YAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;YACjF,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,IAAI,mBAAmB,GAAkB,IAAI,CAAC;YAC9C,SAAS,CAAC;gBACR,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE;oBACpD,GAAG,IAAI;oBACP,QAAQ;oBACR,QAAQ;iBACT,CAAC,CAAC;gBACH,IAAI,IAAI,CAAC,mBAAmB;oBAAE,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAC;gBAC7E,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxB,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ;oBAAE,MAAM;gBACvC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC7B,IAAI,QAAQ,IAAI,yBAAyB;oBAAE,MAAM;YACnD,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;QACvC,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,EAAE,YAAY;YACnD,MAAM,IAAI,GAAG,MAAM,OAAO,CACxB,mBAAmB,EACnB,OAAO,EACP,WAAW,EACX;gBACE,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE;oBACJ,OAAO;oBACP,aAAa;oBACb,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC1C;aACF,CACF,CAAC;YACF,OAAO,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,CAAO;IACzB,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,CAAO,EAAE,IAAY;IACnD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;IACpC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAU,EAAE,MAAc;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IAC9B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAChB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,CAAC;IACxC,MAAM,YAAY,GAAG,IAAI,IAAI,CAC3B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CACrD,CAAC,UAAU,EAAE,CAAC;IACf,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,CAAC;AACX,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,KAAK,GAAG,IAAI,IAAI,EAAE;IAIjD,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACzC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,SAAiB,EACjB,OAAe;IAEf,MAAM,MAAM,GAA6C,EAAE,CAAC;IAC5D,IAAI,MAAM,GAAG,IAAI,IAAI,CAAC,GAAG,SAAS,YAAY,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,YAAY,CAAC,CAAC;IAC7C,OAAO,MAAM,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,IAAI,IAAI,CACvB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAC/D,CAAC;QACF,MAAM,QAAQ,GAAG,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAChE,MAAM,GAAG,IAAI,IAAI,CACf,IAAI,CAAC,GAAG,CACN,QAAQ,CAAC,cAAc,EAAE,EACzB,QAAQ,CAAC,WAAW,EAAE,EACtB,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,CAC1B,CACF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { QuotaApi, QuotaManager } from "./quota.js";
|
|
2
|
+
export type FetchFn = typeof fetch;
|
|
3
|
+
export type GoogleHttp = {
|
|
4
|
+
fetch: FetchFn;
|
|
5
|
+
quota: QuotaManager;
|
|
6
|
+
maxRetries: number;
|
|
7
|
+
sleep: (ms: number) => Promise<void>;
|
|
8
|
+
/** Cap for tests. GSC load-quota advice is wait 15 minutes. */
|
|
9
|
+
maxBackoffMs: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function defaultSleep(ms: number): Promise<void>;
|
|
12
|
+
export declare function googleFetch(http: GoogleHttp, api: QuotaApi, scopeKey: string, url: string, init: RequestInit, cost?: number): Promise<Response>;
|
|
13
|
+
export declare function bearer(token: string, extra?: Record<string, string>): Record<string, string>;
|
|
14
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC;AAEnC,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAIF,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtD;AAaD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,IAAI,SAAI,GACP,OAAO,CAAC,QAAQ,CAAC,CA4BnB;AAED,wBAAgB,MAAM,CACpB,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { QuotaExceededError } from "./errors.js";
|
|
2
|
+
const LOAD_QUOTA_WAIT_MS = 15 * 60_000;
|
|
3
|
+
export function defaultSleep(ms) {
|
|
4
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
5
|
+
}
|
|
6
|
+
function retryAfterMs(res, attempt, maxBackoffMs) {
|
|
7
|
+
const header = res.headers.get("retry-after");
|
|
8
|
+
if (header) {
|
|
9
|
+
const sec = Number(header);
|
|
10
|
+
if (Number.isFinite(sec) && sec >= 0)
|
|
11
|
+
return Math.min(sec * 1000, maxBackoffMs);
|
|
12
|
+
}
|
|
13
|
+
const exp = Math.min(1000 * 2 ** attempt, maxBackoffMs);
|
|
14
|
+
const jitter = Math.floor(Math.random() * 250);
|
|
15
|
+
return exp + jitter;
|
|
16
|
+
}
|
|
17
|
+
export async function googleFetch(http, api, scopeKey, url, init, cost = 1) {
|
|
18
|
+
await http.quota.acquire(api, scopeKey, cost);
|
|
19
|
+
let last;
|
|
20
|
+
for (let n = 0; n <= http.maxRetries; n++) {
|
|
21
|
+
const res = await http.fetch(url, init);
|
|
22
|
+
last = res;
|
|
23
|
+
if (res.status === 429 || res.status >= 500) {
|
|
24
|
+
if (n === http.maxRetries)
|
|
25
|
+
break;
|
|
26
|
+
let wait = retryAfterMs(res, n, http.maxBackoffMs);
|
|
27
|
+
if (api === "gsc.searchAnalytics" && res.status === 429) {
|
|
28
|
+
wait = Math.min(LOAD_QUOTA_WAIT_MS, Math.max(wait, http.maxBackoffMs));
|
|
29
|
+
}
|
|
30
|
+
await http.sleep(wait);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
http.quota.record(api, scopeKey, cost);
|
|
34
|
+
return res;
|
|
35
|
+
}
|
|
36
|
+
if (!last)
|
|
37
|
+
throw new Error("googleFetch: no response");
|
|
38
|
+
if (last.status === 429) {
|
|
39
|
+
throw new QuotaExceededError(api, `${api} returned 429 after retries`, http.maxBackoffMs);
|
|
40
|
+
}
|
|
41
|
+
http.quota.record(api, scopeKey, cost);
|
|
42
|
+
return last;
|
|
43
|
+
}
|
|
44
|
+
export function bearer(token, extra) {
|
|
45
|
+
return { Authorization: `Bearer ${token}`, ...extra };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|