agentlinkops 0.6.1 → 0.6.3
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.mcp.json +0 -0
- package/CHANGELOG.md +17 -0
- package/LICENSE +0 -0
- package/NOTICE +0 -0
- package/README.md +0 -0
- package/bin/agentlinkops.mjs +0 -0
- package/bin/linktrail.mjs +0 -0
- package/cli/adapters/csv.js +0 -0
- package/cli/adapters/sqlite-crm.js +0 -0
- package/cli/adapters/suppliers.js +0 -0
- package/cli/admission.js +130 -0
- package/cli/agent-setup.js +1014 -101
- package/cli/agentlinkops.mjs +0 -0
- package/cli/args.js +0 -0
- package/cli/catalog.js +12837 -4694
- package/cli/check.js +0 -0
- package/cli/citation.js +181 -32
- package/cli/client.js +1 -1
- package/cli/commands.js +3 -3
- package/cli/config.js +2 -1
- package/cli/connection.js +0 -0
- package/cli/context-mcp.js +0 -0
- package/cli/context.js +0 -0
- package/cli/delivery.js +0 -0
- package/cli/disavow.js +54 -0
- package/cli/doctor.js +7 -8
- package/cli/env.js +0 -0
- package/cli/fleet.js +0 -0
- package/cli/gsc-browser.js +0 -0
- package/cli/import.js +0 -0
- package/cli/index-observations.js +89 -0
- package/cli/ledger.js +7 -1
- package/cli/lifecycle.js +40 -0
- package/cli/linktrail.mjs +0 -0
- package/cli/local-result.js +0 -0
- package/cli/main.js +99 -7
- package/cli/mirror.js +0 -0
- package/cli/mix.js +0 -0
- package/cli/platforms.js +0 -0
- package/cli/receipt-performance.js +0 -0
- package/cli/receipts.js +0 -0
- package/cli/report.js +79 -6
- package/cli/setup-plan.js +0 -0
- package/cli/skill.js +41 -4
- package/cli/state.js +0 -0
- package/cli/status.js +0 -0
- package/cli/sync.js +23 -1
- package/package.json +3 -2
- package/references/citation-panels.md +26 -0
- package/references/cli.md +0 -0
- package/references/disavow.md +0 -0
- package/references/discovery-handoff.md +32 -0
- package/references/recipes/catalog.json +148 -0
- package/references/recipes/command-notes.md +9 -0
- package/references/recipes/placement-reconciliation.md +41 -0
- package/references/recipes/qualified-campaign-handoff.md +56 -0
- package/references/recipes/site-context-brief.md +25 -0
- package/references/recipes/sourced-linkable-asset.md +25 -0
- package/references/reports.md +0 -0
- package/scripts/agentlinkops.py +0 -0
- package/scripts/disavow.py +0 -0
- package/scripts/linktrail.py +0 -0
- package/scripts/migrations/001_crm.sql +0 -0
- package/scripts/migrations/002_cloud_events.sql +0 -0
- package/scripts/migrations/003_disavow.sql +0 -0
- package/scripts/migrations/004_placement_costs.sql +0 -0
- package/scripts/report.py +0 -0
- package/shared/admission-contract.js +16 -0
- package/shared/admission-report-contract.js +8 -0
- package/shared/agent-clients.js +0 -0
- package/shared/citation-evidence-contract.js +27 -0
- package/shared/disavow-contract.js +18 -0
- package/shared/index-observation-contract.js +14 -0
- package/shared/lifecycle-contract.js +22 -0
- package/shared/lifecycle-money.js +24 -0
- package/shared/observation-event.js +12 -1
- package/shared/opportunity-record.js +259 -0
- package/shared/response-contract.js +2 -0
- package/shared/search-connection-contract.js +0 -0
- package/skills/agentlinkops-assets/SKILL.md +2 -0
- package/skills/agentlinkops-assets/agents/openai.yaml +0 -0
- package/skills/agentlinkops-campaigns/SKILL.md +5 -1
- package/skills/agentlinkops-campaigns/agents/openai.yaml +0 -0
- package/skills/agentlinkops-connect/SKILL.md +8 -0
- package/skills/agentlinkops-connect/agents/openai.yaml +0 -0
- package/skills/agentlinkops-connect/references/agentlinkops.md +9 -5
- package/skills/agentlinkops-crm/SKILL.md +2 -0
- package/skills/agentlinkops-crm/agents/openai.yaml +0 -0
- package/skills/agentlinkops-discovery/SKILL.md +17 -0
- package/skills/content-defingerprinting/SKILL.md +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/README.md +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/UPSTREAM.json +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/revendor.sh +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/vendor/LICENSE.upstream +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/vendor/clean_text.py +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/vendor/common.py +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/vendor/inspect_text.py +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/vendor/score_stylometry.py +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/vendor/text_unicode.py +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/verify-vendor.py +0 -0
- package/skills/content-defingerprinting/scripts/watermarks/wm-scan.py +0 -0
- package/skills/internal-linking-optimizer/SKILL.md +0 -0
- package/skills/internal-linking-optimizer/references/source-prompt.md +0 -0
- package/skills/pre-publish-review/SKILL.md +0 -0
- package/skills/source-cited-content-builder/SKILL.md +0 -0
- package/skills/source-cited-content-builder/references/source-prompt.md +0 -0
- package/skills/source-cited-humanizer/SKILL.md +0 -0
- package/src/citations/adapter.js +102 -21
- package/src/citations/alert.js +38 -13
- package/src/citations/browser/engine.js +145 -50
- package/src/citations/browser/gen/core/providers/_shared/rawSourcesDom.js +0 -0
- package/src/citations/browser/gen/core/providers/_shared/resetProviderPage.js +0 -0
- package/src/citations/browser/gen/core/providers/_shared/sourceUtils.js +0 -0
- package/src/citations/browser/gen/core/providers/ai-overview/index.js +0 -0
- package/src/citations/browser/gen/core/providers/ai-overview/lib/expand.js +0 -0
- package/src/citations/browser/gen/core/providers/ai-overview/lib/extractSources.js +0 -0
- package/src/citations/browser/gen/core/providers/ai-overview/lib/pageLifecycle.js +0 -0
- package/src/citations/browser/gen/core/providers/ai-overview/lib/session.js +0 -0
- package/src/citations/browser/gen/core/providers/chatgpt/index.js +0 -0
- package/src/citations/browser/gen/core/providers/chatgpt/lib/dismissAuthModal.js +0 -0
- package/src/citations/browser/gen/core/providers/chatgpt/lib/extractSources.js +0 -0
- package/src/citations/browser/gen/core/providers/chatgpt/lib/pageLifecycle.js +0 -0
- package/src/citations/browser/gen/core/providers/claude/index.js +0 -0
- package/src/citations/browser/gen/core/providers/claude/lib/extractSources.js +0 -0
- package/src/citations/browser/gen/core/providers/claude/lib/pageLifecycle.js +0 -0
- package/src/citations/browser/gen/core/providers/gemini/index.js +0 -0
- package/src/citations/browser/gen/core/providers/gemini/lib/extractSources.js +0 -0
- package/src/citations/browser/gen/core/providers/gemini/lib/pageLifecycle.js +0 -0
- package/src/citations/browser/gen/core/providers/gemini/lib/session.js +0 -0
- package/src/citations/browser/gen/core/providers/index.js +0 -0
- package/src/citations/browser/gen/core/providers/perplexity/index.js +0 -0
- package/src/citations/browser/gen/core/providers/perplexity/lib/extractSources.js +0 -0
- package/src/citations/browser/gen/core/providers/perplexity/lib/navigation.js +0 -0
- package/src/citations/browser/gen/lib/browser/camoufox.js +0 -0
- package/src/citations/browser/gen/lib/browser/display.js +0 -0
- package/src/citations/browser/gen/lib/browser/domOps.js +0 -0
- package/src/citations/browser/gen/lib/browser/humanBehavior.js +0 -0
- package/src/citations/browser/gen/lib/browser/navigate.js +0 -0
- package/src/citations/browser/gen/lib/extraction/sourceUtils.js +0 -0
- package/src/citations/browser/gen/lib/input/editor/clearInput.js +0 -0
- package/src/citations/browser/gen/lib/input/editor/findEditor.js +0 -0
- package/src/citations/browser/gen/lib/input/editor/promptInput.js +0 -0
- package/src/citations/browser/gen/lib/input/markdown/converter.js +0 -0
- package/src/citations/browser/gen/lib/input/markdown/toMarkdown.js +0 -0
- package/src/citations/browser/gen/lib/input/response/detectBotPage.js +0 -0
- package/src/citations/browser/gen/lib/input/response/isGenerating.js +0 -0
- package/src/citations/browser/gen/lib/input/response/waitForFinish.js +0 -0
- package/src/citations/browser/gen/lib/input/sources/findButton.js +0 -0
- package/src/citations/browser/gen/lib/input/sources/openPanel.js +0 -0
- package/src/citations/browser/gen/utils/agent-constants.js +0 -0
- package/src/citations/browser/providers.js +3 -1
- package/src/citations/browser/shims/errors.js +0 -0
- package/src/citations/browser/shims/types.js +0 -0
- package/src/citations/browser/shims/utils.js +1 -0
- package/src/citations/contract.js +55 -9
- package/src/citations/inventory.js +106 -0
- package/src/citations/login.js +122 -0
- package/src/citations/match.js +12 -0
- package/src/citations/panel-builder.js +44 -39
- package/src/citations/report.js +88 -21
- package/src/citations/runner.js +59 -31
- package/src/citations/stats.js +133 -61
- package/src/citations/sync.js +131 -0
- package/src/citations/watch.js +57 -77
- package/src/competitors/contract.js +0 -0
- package/src/competitors/domain-mix.js +0 -0
- package/src/context/ga4.js +0 -0
- package/src/context/gsc.js +0 -0
- package/src/context/site-profile.js +0 -0
- package/src/context/util.js +0 -0
- package/src/context-tool-registry.js +0 -0
- package/src/corpus/acquire.js +47 -8
- package/src/corpus/seeds.js +132 -19
- package/src/discovery/contract.js +0 -0
- package/src/discovery/import.js +0 -0
- package/src/evidence-reference.js +112 -0
- package/src/index-observation.js +161 -0
- package/src/locator.js +112 -0
- package/src/tool-views.js +6 -2
- package/src/verifier/fetch.js +42 -6
- package/src/verifier/index.js +0 -0
- package/src/verifier/observation-kind.js +0 -0
- package/src/verifier/parser.js +0 -0
- package/src/verifier/readiness.js +0 -0
- package/src/verifier/render-evidence.js +0 -0
- package/src/verifier/robots.js +0 -0
- package/src/verifier/transition.js +0 -0
- package/src/verifier/url.js +0 -0
- package/templates/SITE.template.md +0 -0
- package/templates/campaigns.v1.json +0 -0
- package/src/citations/browser/gen/core/providers/_shared/google.js +0 -4
- package/src/citations/browser/gen/core/providers/types.js +0 -0
- package/src/citations/browser/gen/lib/browser/playwrightCompat.js +0 -321
- package/src/citations/browser/gen/lib/browser/proxy/forwarder.js +0 -251
- package/src/citations/browser/gen/lib/browser/runtimeTypes.js +0 -0
- package/src/citations/browser/gen/lib/input/editor/assertNotBlocked.js +0 -54
- package/src/citations/browser/gen/lib/input/editor/findSendButton.js +0 -21
- package/src/citations/browser/gen/lib/input/response/getText.js +0 -10
- package/src/citations/fixtures/dataforseo-aio.json +0 -82
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
request as httpRequest
|
|
3
|
-
} from "node:http";
|
|
4
|
-
import { request as httpsRequest } from "node:https";
|
|
5
|
-
import { connect as netConnect } from "node:net";
|
|
6
|
-
import { connect as tlsConnect } from "node:tls";
|
|
7
|
-
const SOCKET_TIMEOUT_MS = 3e4;
|
|
8
|
-
function buildBasicAuthHeader(proxy) {
|
|
9
|
-
if (!proxy.username && !proxy.password) return null;
|
|
10
|
-
const token = Buffer.from(
|
|
11
|
-
`${proxy.username ?? ""}:${proxy.password ?? ""}`
|
|
12
|
-
).toString("base64");
|
|
13
|
-
return `Basic ${token}`;
|
|
14
|
-
}
|
|
15
|
-
function sanitizeHeaders(headers) {
|
|
16
|
-
const nextHeaders = { ...headers };
|
|
17
|
-
delete nextHeaders["proxy-authorization"];
|
|
18
|
-
delete nextHeaders["proxy-connection"];
|
|
19
|
-
delete nextHeaders["Proxy-Authorization"];
|
|
20
|
-
delete nextHeaders["Proxy-Connection"];
|
|
21
|
-
return nextHeaders;
|
|
22
|
-
}
|
|
23
|
-
function formatHttpTarget(request) {
|
|
24
|
-
if (!request.url) {
|
|
25
|
-
throw new Error("Proxy request missing URL");
|
|
26
|
-
}
|
|
27
|
-
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(request.url)) {
|
|
28
|
-
return new URL(request.url);
|
|
29
|
-
}
|
|
30
|
-
if (!request.headers.host) {
|
|
31
|
-
throw new Error("Proxy request missing Host header");
|
|
32
|
-
}
|
|
33
|
-
return new URL(`http://${request.headers.host}${request.url}`);
|
|
34
|
-
}
|
|
35
|
-
function parseAuthority(authority) {
|
|
36
|
-
if (authority.startsWith("[")) {
|
|
37
|
-
const closingBracket = authority.indexOf("]");
|
|
38
|
-
if (closingBracket === -1) {
|
|
39
|
-
throw new Error(`Invalid authority: ${authority}`);
|
|
40
|
-
}
|
|
41
|
-
const host2 = authority.slice(1, closingBracket);
|
|
42
|
-
const portPart = authority.slice(closingBracket + 1);
|
|
43
|
-
const port2 = portPart.startsWith(":") ? Number(portPart.slice(1)) : 443;
|
|
44
|
-
if (!Number.isFinite(port2)) {
|
|
45
|
-
throw new Error(`Invalid authority port: ${authority}`);
|
|
46
|
-
}
|
|
47
|
-
return { host: host2, port: port2 };
|
|
48
|
-
}
|
|
49
|
-
const separator = authority.lastIndexOf(":");
|
|
50
|
-
if (separator === -1) {
|
|
51
|
-
return { host: authority, port: 443 };
|
|
52
|
-
}
|
|
53
|
-
const host = authority.slice(0, separator);
|
|
54
|
-
const port = Number(authority.slice(separator + 1));
|
|
55
|
-
if (!host || !Number.isFinite(port)) {
|
|
56
|
-
throw new Error(`Invalid authority: ${authority}`);
|
|
57
|
-
}
|
|
58
|
-
return { host, port };
|
|
59
|
-
}
|
|
60
|
-
function connectTcp(host, port) {
|
|
61
|
-
return new Promise((resolve, reject) => {
|
|
62
|
-
const socket = netConnect({ host, port });
|
|
63
|
-
const onError = (error) => {
|
|
64
|
-
cleanup();
|
|
65
|
-
reject(error);
|
|
66
|
-
};
|
|
67
|
-
const onConnect = () => {
|
|
68
|
-
cleanup();
|
|
69
|
-
socket.setNoDelay(true);
|
|
70
|
-
socket.setTimeout(SOCKET_TIMEOUT_MS, () => {
|
|
71
|
-
socket.destroy(new Error("socket timeout"));
|
|
72
|
-
});
|
|
73
|
-
resolve(socket);
|
|
74
|
-
};
|
|
75
|
-
const cleanup = () => {
|
|
76
|
-
socket.off("error", onError);
|
|
77
|
-
socket.off("connect", onConnect);
|
|
78
|
-
};
|
|
79
|
-
socket.once("error", onError);
|
|
80
|
-
socket.once("connect", onConnect);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
function connectTls(host, port) {
|
|
84
|
-
return new Promise((resolve, reject) => {
|
|
85
|
-
const socket = tlsConnect({
|
|
86
|
-
host,
|
|
87
|
-
port,
|
|
88
|
-
servername: host,
|
|
89
|
-
// Proxy providers (e.g. BrightData) may use custom CA certs.
|
|
90
|
-
// rejectUnauthorized applies only to the proxy TLS hop, not to the
|
|
91
|
-
// end-to-end TLS inside the CONNECT tunnel (which the browser validates).
|
|
92
|
-
rejectUnauthorized: false
|
|
93
|
-
});
|
|
94
|
-
const onError = (error) => {
|
|
95
|
-
cleanup();
|
|
96
|
-
reject(error);
|
|
97
|
-
};
|
|
98
|
-
const onSecureConnect = () => {
|
|
99
|
-
cleanup();
|
|
100
|
-
socket.setNoDelay(true);
|
|
101
|
-
socket.setTimeout(SOCKET_TIMEOUT_MS, () => {
|
|
102
|
-
socket.destroy(new Error("socket timeout"));
|
|
103
|
-
});
|
|
104
|
-
resolve(socket);
|
|
105
|
-
};
|
|
106
|
-
const cleanup = () => {
|
|
107
|
-
socket.off("error", onError);
|
|
108
|
-
socket.off("secureConnect", onSecureConnect);
|
|
109
|
-
};
|
|
110
|
-
socket.once("error", onError);
|
|
111
|
-
socket.once("secureConnect", onSecureConnect);
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
function readUntilAny(socket, ...delimiters) {
|
|
115
|
-
return new Promise((resolve, reject) => {
|
|
116
|
-
const delimiterBuffers = delimiters.map((d) => Buffer.from(d));
|
|
117
|
-
const chunks = [];
|
|
118
|
-
let total = 0;
|
|
119
|
-
const onData = (chunk) => {
|
|
120
|
-
chunks.push(chunk);
|
|
121
|
-
total += chunk.length;
|
|
122
|
-
const payload = Buffer.concat(chunks, total);
|
|
123
|
-
for (const delimiterBuffer of delimiterBuffers) {
|
|
124
|
-
const index = payload.indexOf(delimiterBuffer);
|
|
125
|
-
if (index === -1) continue;
|
|
126
|
-
cleanup();
|
|
127
|
-
const end = index + delimiterBuffer.length;
|
|
128
|
-
const head = payload.subarray(0, end);
|
|
129
|
-
const tail = payload.subarray(end);
|
|
130
|
-
if (tail.length > 0) {
|
|
131
|
-
socket.unshift(tail);
|
|
132
|
-
}
|
|
133
|
-
resolve(head);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
const onError = (error) => {
|
|
138
|
-
cleanup();
|
|
139
|
-
reject(error);
|
|
140
|
-
};
|
|
141
|
-
const onClose = () => {
|
|
142
|
-
cleanup();
|
|
143
|
-
reject(new Error("socket closed before response headers were received"));
|
|
144
|
-
};
|
|
145
|
-
const cleanup = () => {
|
|
146
|
-
socket.off("data", onData);
|
|
147
|
-
socket.off("error", onError);
|
|
148
|
-
socket.off("close", onClose);
|
|
149
|
-
};
|
|
150
|
-
socket.on("data", onData);
|
|
151
|
-
socket.once("error", onError);
|
|
152
|
-
socket.once("close", onClose);
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
async function createTunnelSocket(proxy, targetHost, targetPort) {
|
|
156
|
-
const socket = proxy.scheme === "https" ? await connectTls(proxy.host, proxy.port) : await connectTcp(proxy.host, proxy.port);
|
|
157
|
-
const authHeader = buildBasicAuthHeader(proxy);
|
|
158
|
-
const requestLines = [
|
|
159
|
-
`CONNECT ${targetHost}:${targetPort} HTTP/1.1`,
|
|
160
|
-
`Host: ${targetHost}:${targetPort}`,
|
|
161
|
-
"Proxy-Connection: Keep-Alive"
|
|
162
|
-
];
|
|
163
|
-
if (authHeader) {
|
|
164
|
-
requestLines.push(`Proxy-Authorization: ${authHeader}`);
|
|
165
|
-
}
|
|
166
|
-
requestLines.push("", "");
|
|
167
|
-
socket.write(requestLines.join("\r\n"));
|
|
168
|
-
const responseHead = await readUntilAny(socket, "\r\n\r\n", "\n\n");
|
|
169
|
-
const statusLine = responseHead.toString("latin1").split(/\r?\n/, 1)[0] ?? "";
|
|
170
|
-
if (!/^HTTP\/1\.[01] 200\b/i.test(statusLine)) {
|
|
171
|
-
socket.destroy();
|
|
172
|
-
throw new Error(`Proxy CONNECT failed: ${statusLine || "no response"}`);
|
|
173
|
-
}
|
|
174
|
-
return socket;
|
|
175
|
-
}
|
|
176
|
-
function handleProxyError(response, statusCode, error) {
|
|
177
|
-
if (response.headersSent) {
|
|
178
|
-
response.destroy(error instanceof Error ? error : void 0);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
response.writeHead(statusCode, { "Content-Type": "text/plain" });
|
|
182
|
-
response.end(error instanceof Error ? error.message : "proxy error");
|
|
183
|
-
}
|
|
184
|
-
async function handleHttpProxyRequest(request, response, proxy, trackSocket) {
|
|
185
|
-
const target = formatHttpTarget(request);
|
|
186
|
-
const proxyAuthHeader = buildBasicAuthHeader(proxy);
|
|
187
|
-
const transport = proxy.scheme === "https" ? httpsRequest : httpRequest;
|
|
188
|
-
const upstreamRequest = transport(
|
|
189
|
-
{
|
|
190
|
-
host: proxy.host,
|
|
191
|
-
port: proxy.port,
|
|
192
|
-
method: request.method,
|
|
193
|
-
path: target.toString(),
|
|
194
|
-
headers: {
|
|
195
|
-
...sanitizeHeaders(request.headers),
|
|
196
|
-
...proxyAuthHeader ? { "Proxy-Authorization": proxyAuthHeader } : {}
|
|
197
|
-
},
|
|
198
|
-
agent: false,
|
|
199
|
-
// Proxy providers may use custom CA certs; only disable for proxy hop.
|
|
200
|
-
rejectUnauthorized: false
|
|
201
|
-
},
|
|
202
|
-
(upstreamResponse) => {
|
|
203
|
-
response.writeHead(
|
|
204
|
-
upstreamResponse.statusCode ?? 502,
|
|
205
|
-
upstreamResponse.statusMessage,
|
|
206
|
-
upstreamResponse.headers
|
|
207
|
-
);
|
|
208
|
-
upstreamResponse.pipe(response);
|
|
209
|
-
}
|
|
210
|
-
);
|
|
211
|
-
upstreamRequest.on("socket", (socket) => {
|
|
212
|
-
trackSocket(socket);
|
|
213
|
-
});
|
|
214
|
-
upstreamRequest.on("error", (error) => {
|
|
215
|
-
handleProxyError(response, 502, error);
|
|
216
|
-
});
|
|
217
|
-
request.pipe(upstreamRequest);
|
|
218
|
-
}
|
|
219
|
-
function relaySockets(clientSocket, upstreamSocket) {
|
|
220
|
-
const destroyPair = () => {
|
|
221
|
-
clientSocket.destroy();
|
|
222
|
-
upstreamSocket.destroy();
|
|
223
|
-
};
|
|
224
|
-
clientSocket.on("error", destroyPair);
|
|
225
|
-
upstreamSocket.on("error", destroyPair);
|
|
226
|
-
clientSocket.on("close", () => upstreamSocket.destroy());
|
|
227
|
-
upstreamSocket.on("close", () => clientSocket.destroy());
|
|
228
|
-
clientSocket.pipe(upstreamSocket);
|
|
229
|
-
upstreamSocket.pipe(clientSocket);
|
|
230
|
-
}
|
|
231
|
-
function checkProxyReachable(host, port, timeoutMs = 2e3) {
|
|
232
|
-
return new Promise((resolve) => {
|
|
233
|
-
const socket = netConnect({ host, port });
|
|
234
|
-
const timer = setTimeout(() => {
|
|
235
|
-
socket.destroy();
|
|
236
|
-
resolve(false);
|
|
237
|
-
}, timeoutMs);
|
|
238
|
-
socket.once("connect", () => {
|
|
239
|
-
clearTimeout(timer);
|
|
240
|
-
socket.destroy();
|
|
241
|
-
resolve(true);
|
|
242
|
-
});
|
|
243
|
-
socket.once("error", () => {
|
|
244
|
-
clearTimeout(timer);
|
|
245
|
-
resolve(false);
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
export {
|
|
250
|
-
checkProxyReachable
|
|
251
|
-
};
|
|
File without changes
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { ExternalServiceError } from "../../../../shims/errors.js";
|
|
2
|
-
async function detectEditorBlocker(page, input) {
|
|
3
|
-
const box = await input.boundingBox().catch(() => null);
|
|
4
|
-
if (!box || box.width < 8 || box.height < 8) {
|
|
5
|
-
return { blocked: false, reason: null };
|
|
6
|
-
}
|
|
7
|
-
const insetX = Math.max(6, Math.min(24, box.width * 0.12));
|
|
8
|
-
const insetY = Math.max(6, Math.min(18, box.height * 0.2));
|
|
9
|
-
const points = [
|
|
10
|
-
{ x: box.x + box.width / 2, y: box.y + box.height / 2 },
|
|
11
|
-
{ x: box.x + insetX, y: box.y + insetY },
|
|
12
|
-
{ x: box.x + box.width - insetX, y: box.y + insetY }
|
|
13
|
-
];
|
|
14
|
-
return await page.evaluate((samples) => {
|
|
15
|
-
const isEditorLike = (element) => Boolean(
|
|
16
|
-
element?.closest(
|
|
17
|
-
'[contenteditable="true"], textarea, input, [role="textbox"], [role="combobox"]'
|
|
18
|
-
)
|
|
19
|
-
);
|
|
20
|
-
for (const sample of samples) {
|
|
21
|
-
const top = document.elementFromPoint(sample.x, sample.y);
|
|
22
|
-
if (!top) continue;
|
|
23
|
-
if (isEditorLike(top)) continue;
|
|
24
|
-
const blocker = top.closest(
|
|
25
|
-
'[role="dialog"], [aria-modal="true"], [popover], [data-state="open"]'
|
|
26
|
-
) || top;
|
|
27
|
-
if (!(blocker instanceof HTMLElement)) continue;
|
|
28
|
-
const style = window.getComputedStyle(blocker);
|
|
29
|
-
if (style.display === "none" || style.visibility === "hidden" || style.pointerEvents === "none") {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
const rect = blocker.getBoundingClientRect();
|
|
33
|
-
if (rect.width < 120 || rect.height < 40) continue;
|
|
34
|
-
const text = (blocker.textContent || "").replace(/\s+/g, " ").trim();
|
|
35
|
-
const label = blocker.getAttribute("aria-label") || blocker.getAttribute("role") || blocker.tagName.toLowerCase();
|
|
36
|
-
return {
|
|
37
|
-
blocked: true,
|
|
38
|
-
reason: `${label}:${text.slice(0, 120)}`
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
return { blocked: false, reason: null };
|
|
42
|
-
}, points);
|
|
43
|
-
}
|
|
44
|
-
async function ensureEditorNotBlocked(page, input, provider) {
|
|
45
|
-
const result = await detectEditorBlocker(page, input);
|
|
46
|
-
if (!result.blocked) return;
|
|
47
|
-
throw new ExternalServiceError(
|
|
48
|
-
provider,
|
|
49
|
-
`Editor blocked by overlay: ${result.reason ?? "unknown blocker"}`
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
export {
|
|
53
|
-
ensureEditorNotBlocked
|
|
54
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { PROVIDER_SUBMIT_BTN_SELECTORS } from "../../../../shims/utils.js";
|
|
2
|
-
async function findEnabledSendButton(page, provider) {
|
|
3
|
-
const selectors = PROVIDER_SUBMIT_BTN_SELECTORS[provider] || [];
|
|
4
|
-
for (const selector of selectors) {
|
|
5
|
-
const buttons = page.locator(selector);
|
|
6
|
-
const count = await buttons.count();
|
|
7
|
-
for (let i = 0; i < count; i++) {
|
|
8
|
-
const btn = buttons.nth(i);
|
|
9
|
-
try {
|
|
10
|
-
if (await btn.isVisible() && await btn.isEnabled()) {
|
|
11
|
-
return btn;
|
|
12
|
-
}
|
|
13
|
-
} catch {
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
export {
|
|
20
|
-
findEnabledSendButton
|
|
21
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { PROVIDER_MODEL_RESPONSE_SELECTORS } from "../../../../shims/utils.js";
|
|
2
|
-
async function getText(page, provider) {
|
|
3
|
-
return await page.runDomOp("response-text", {
|
|
4
|
-
provider,
|
|
5
|
-
selectors: PROVIDER_MODEL_RESPONSE_SELECTORS[provider] || []
|
|
6
|
-
});
|
|
7
|
-
}
|
|
8
|
-
export {
|
|
9
|
-
getText
|
|
10
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "0.0.0",
|
|
3
|
-
"status_code": 20000,
|
|
4
|
-
"status_message": "Ok.",
|
|
5
|
-
"cost": 0.0012,
|
|
6
|
-
"tasks_count": 1,
|
|
7
|
-
"tasks_error": 0,
|
|
8
|
-
"tasks": [
|
|
9
|
-
{
|
|
10
|
-
"id": "09211815-1535-0067-0000-7b8e2b4e5c91",
|
|
11
|
-
"status_code": 20000,
|
|
12
|
-
"status_message": "Ok.",
|
|
13
|
-
"cost": 0.0012,
|
|
14
|
-
"result_count": 1,
|
|
15
|
-
"result": [
|
|
16
|
-
{
|
|
17
|
-
"keyword": "what is backlink monitoring",
|
|
18
|
-
"type": "organic",
|
|
19
|
-
"se_domain": "google.com",
|
|
20
|
-
"location_code": 2840,
|
|
21
|
-
"language_code": "en",
|
|
22
|
-
"check_url": "https://www.google.com/search?q=what%20is%20backlink%20monitoring&num=10&hl=en&gl=us&gws_rd=cr",
|
|
23
|
-
"datetime": "2026-09-18 18:15:03 +00:00",
|
|
24
|
-
"item_types": ["ai_overview", "organic", "featured_snippet", "people_also_ask"],
|
|
25
|
-
"se_results_count": 12400000,
|
|
26
|
-
"items": [
|
|
27
|
-
{
|
|
28
|
-
"type": "ai_overview",
|
|
29
|
-
"rank_group": 1,
|
|
30
|
-
"rank_absolute": 1,
|
|
31
|
-
"position": "top",
|
|
32
|
-
"xpath": "/html[1]/body[1]/div[6]/div[2]/div[9]/div[1]/div[2]/div[2]/div[1]/div[1]",
|
|
33
|
-
"text": "Backlink monitoring is the process of regularly tracking and analyzing the links pointing to your website from other sites. It involves checking whether your existing backlinks are still active, identifying new backlinks as they appear, and analyzing the quality and relevance of those links. Effective backlink monitoring helps you maintain a healthy link profile, identify potentially harmful links, and find opportunities for new link building. Common tools for backlink monitoring include Ahrefs, Semrush, and Moz, which provide comprehensive dashboards for tracking your link profile over time.",
|
|
34
|
-
"items": [
|
|
35
|
-
{
|
|
36
|
-
"type": "ai_overview_item",
|
|
37
|
-
"source": "backlinkmonitoring.ai",
|
|
38
|
-
"domain": "backlinkmonitoring.ai",
|
|
39
|
-
"title": "What Is Backlink Monitoring and Why It Matters",
|
|
40
|
-
"url": "https://backlinkmonitoring.ai/blog/what-is-backlink-monitoring",
|
|
41
|
-
"snippet": "Backlink monitoring is the practice of regularly tracking and analyzing inbound links to your website..."
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"type": "ai_overview_item",
|
|
45
|
-
"source": "adaptify.ai",
|
|
46
|
-
"domain": "adaptify.ai",
|
|
47
|
-
"title": "What is Backlink Monitoring and Why Your SEO Needs It",
|
|
48
|
-
"url": "https://adaptify.ai/blog/what-is-backlink-monitoring-and-why-your-seo-needs-it",
|
|
49
|
-
"snippet": "Effective backlink monitoring helps you maintain a healthy link profile and identify harmful links..."
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"type": "ai_overview_item",
|
|
53
|
-
"source": "lynkdog.com",
|
|
54
|
-
"domain": "lynkdog.com",
|
|
55
|
-
"title": "Backlink Monitoring: A Complete Beginner's Guide",
|
|
56
|
-
"url": "https://lynkdog.com/blog/backlink-monitoring-beginners-guide",
|
|
57
|
-
"snippet": "Backlink monitoring involves checking whether your existing backlinks are still active..."
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"type": "ai_overview_item",
|
|
61
|
-
"source": "brand24.com",
|
|
62
|
-
"domain": "brand24.com",
|
|
63
|
-
"title": "Backlinks Monitoring 101: Tools, Tips, and Best Practices",
|
|
64
|
-
"url": "https://brand24.com/blog/backlinks-monitoring-101/",
|
|
65
|
-
"snippet": "Common tools for backlink monitoring include Ahrefs, Semrush, and Moz..."
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"type": "organic",
|
|
71
|
-
"rank_group": 1,
|
|
72
|
-
"rank_absolute": 2,
|
|
73
|
-
"url": "https://backlinko.com/hub/seo/backlinks",
|
|
74
|
-
"domain": "backlinko.com",
|
|
75
|
-
"title": "What Are Backlinks in SEO & Why You Need Them"
|
|
76
|
-
}
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
}
|