web-access-cli 0.1.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -0
  3. package/README_CN.md +268 -0
  4. package/THIRD_PARTY_NOTICES.md +48 -0
  5. package/dist/cli.js +197 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config/config.js +463 -0
  8. package/dist/config/config.js.map +1 -0
  9. package/dist/config/edit.js +126 -0
  10. package/dist/config/edit.js.map +1 -0
  11. package/dist/core/diagnostics.js +94 -0
  12. package/dist/core/diagnostics.js.map +1 -0
  13. package/dist/core/errors.js +47 -0
  14. package/dist/core/errors.js.map +1 -0
  15. package/dist/core/router.js +320 -0
  16. package/dist/core/router.js.map +1 -0
  17. package/dist/core/schema.js +120 -0
  18. package/dist/core/schema.js.map +1 -0
  19. package/dist/core/types.js +22 -0
  20. package/dist/core/types.js.map +1 -0
  21. package/dist/providers/anysearch.js +225 -0
  22. package/dist/providers/anysearch.js.map +1 -0
  23. package/dist/providers/common.js +210 -0
  24. package/dist/providers/common.js.map +1 -0
  25. package/dist/providers/extract.js +155 -0
  26. package/dist/providers/extract.js.map +1 -0
  27. package/dist/providers/registry.js +31 -0
  28. package/dist/providers/registry.js.map +1 -0
  29. package/dist/providers/rsc.js +109 -0
  30. package/dist/providers/rsc.js.map +1 -0
  31. package/dist/providers/search.js +178 -0
  32. package/dist/providers/search.js.map +1 -0
  33. package/dist/providers/xcrawl.js +170 -0
  34. package/dist/providers/xcrawl.js.map +1 -0
  35. package/dist/transport/http.js +175 -0
  36. package/dist/transport/http.js.map +1 -0
  37. package/dist/version.js +2 -0
  38. package/dist/version.js.map +1 -0
  39. package/package.json +61 -0
  40. package/schemas/config.schema.json +210 -0
  41. package/schemas/extractRequest.schema.json +21 -0
  42. package/schemas/output.schema.json +435 -0
  43. package/schemas/searchRequest.schema.json +57 -0
@@ -0,0 +1,170 @@
1
+ import { redactText, WebAccessError } from "../core/errors.js";
2
+ import { buildEndpoint } from "../transport/http.js";
3
+ import { assertOk, freshnessStartDate, normalizeHits, parseJsonResponse, providerHeaders, ref, requireBaseUrl, requireCredential, searchQueryWithDomains, } from "./common.js";
4
+ function isRecord(value) {
5
+ return !!value && typeof value === "object" && !Array.isArray(value);
6
+ }
7
+ function stringField(value) {
8
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
9
+ }
10
+ function responseMessage(value) {
11
+ for (const candidate of [
12
+ value.message,
13
+ value.error,
14
+ isRecord(value.data) ? value.data.message : undefined,
15
+ isRecord(value.data) ? value.data.error : undefined,
16
+ ]) {
17
+ if (typeof candidate === "string" && candidate.trim())
18
+ return candidate.trim().slice(0, 500);
19
+ if (isRecord(candidate)) {
20
+ const nested = stringField(candidate.message) ?? stringField(candidate.error);
21
+ if (nested)
22
+ return nested.slice(0, 500);
23
+ }
24
+ }
25
+ return "上游任务失败";
26
+ }
27
+ function assertCompleted(parsed, request) {
28
+ if (parsed.status === "completed")
29
+ return;
30
+ if (parsed.status === "failed") {
31
+ const message = redactText(responseMessage(parsed), [
32
+ request.instance.apiKey,
33
+ ]);
34
+ throw new WebAccessError("provider_error", `XCrawl 任务失败: ${message}`, {
35
+ provider: ref(request.instance),
36
+ retryable: true,
37
+ raw: parsed,
38
+ });
39
+ }
40
+ throw new WebAccessError("invalid_response", "XCrawl 返回未知任务状态", {
41
+ provider: ref(request.instance),
42
+ retryable: true,
43
+ raw: parsed,
44
+ });
45
+ }
46
+ function queryWithFilters(request) {
47
+ const parts = [
48
+ searchQueryWithDomains(request.query, request.includeDomains, request.excludeDomains),
49
+ ];
50
+ if (request.instance.searchFilterMode === "best_effort" && request.freshness)
51
+ parts.push(`after:${freshnessStartDate(request.freshness)}`);
52
+ return parts.join(" ");
53
+ }
54
+ function requestHeaders(request) {
55
+ const key = requireCredential(request.instance);
56
+ const headers = providerHeaders(request.instance, {
57
+ "Content-Type": "application/json",
58
+ Accept: "application/json",
59
+ });
60
+ for (const name of Object.keys(headers))
61
+ if (name.toLowerCase() === "authorization")
62
+ delete headers[name];
63
+ headers.Authorization = `Bearer ${key}`;
64
+ return headers;
65
+ }
66
+ function normalizedMarkdown(value) {
67
+ return value
68
+ .replace(/\r\n/g, "\n")
69
+ .replace(/[ \t]+\n/g, "\n")
70
+ .trim();
71
+ }
72
+ function httpUrl(value) {
73
+ if (typeof value !== "string")
74
+ return undefined;
75
+ try {
76
+ const parsed = new URL(value);
77
+ return parsed.protocol === "http:" || parsed.protocol === "https:"
78
+ ? parsed.toString()
79
+ : undefined;
80
+ }
81
+ catch {
82
+ return undefined;
83
+ }
84
+ }
85
+ const xcrawl = {
86
+ type: "xcrawl",
87
+ capabilities: ["search", "extract"],
88
+ isConfigured: (instance) => !!instance.apiKey && !!instance.baseUrl,
89
+ async search(request) {
90
+ if (request.freshness &&
91
+ (request.instance.searchFilterMode ?? "strict") === "strict")
92
+ throw new WebAccessError("provider_unavailable", "XCrawl 严格模式不支持 freshness", { provider: ref(request.instance), retryable: true });
93
+ const response = await request.transport.request(buildEndpoint(requireBaseUrl(request.instance), "v1/search"), {
94
+ method: "POST",
95
+ headers: requestHeaders(request),
96
+ body: JSON.stringify({
97
+ query: queryWithFilters(request),
98
+ limit: request.includeDomains.length || request.excludeDomains.length
99
+ ? 20
100
+ : request.limit,
101
+ }),
102
+ signal: request.signal,
103
+ maxResponseBytes: request.maxResponseBytes,
104
+ });
105
+ assertOk(response, request.instance);
106
+ const parsed = parseJsonResponse(response, request.instance);
107
+ assertCompleted(parsed, request);
108
+ if (!isRecord(parsed.data) || !Array.isArray(parsed.data.data))
109
+ throw new WebAccessError("invalid_response", "XCrawl Search 返回缺少 data.data", {
110
+ provider: ref(request.instance),
111
+ retryable: true,
112
+ raw: parsed,
113
+ });
114
+ return {
115
+ data: {
116
+ results: normalizeHits(parsed.data.data, request.limit, request.includeDomains, request.excludeDomains),
117
+ },
118
+ raw: parsed,
119
+ };
120
+ },
121
+ async extract(request) {
122
+ const response = await request.transport.request(buildEndpoint(requireBaseUrl(request.instance), "v1/scrape"), {
123
+ method: "POST",
124
+ headers: requestHeaders(request),
125
+ body: JSON.stringify({
126
+ url: request.url,
127
+ mode: "sync",
128
+ output: { formats: ["markdown"] },
129
+ }),
130
+ signal: request.signal,
131
+ maxResponseBytes: request.maxResponseBytes,
132
+ });
133
+ assertOk(response, request.instance);
134
+ const parsed = parseJsonResponse(response, request.instance);
135
+ assertCompleted(parsed, request);
136
+ if (!isRecord(parsed.data))
137
+ throw new WebAccessError("invalid_response", "XCrawl Scrape 返回缺少 data", {
138
+ provider: ref(request.instance),
139
+ retryable: true,
140
+ raw: parsed,
141
+ });
142
+ const content = stringField(parsed.data.markdown);
143
+ if (!content)
144
+ throw new WebAccessError("no_usable_content", "XCrawl Scrape 没有返回 Markdown 正文", {
145
+ provider: ref(request.instance),
146
+ retryable: true,
147
+ raw: parsed,
148
+ });
149
+ const markdown = normalizedMarkdown(content);
150
+ const metadata = isRecord(parsed.data.metadata)
151
+ ? parsed.data.metadata
152
+ : undefined;
153
+ const title = stringField(metadata?.title) ??
154
+ /^#\s+(.+)$/m.exec(markdown)?.[1]?.trim() ??
155
+ "";
156
+ return {
157
+ data: {
158
+ document: {
159
+ sourceUrl: httpUrl(metadata?.final_url) ?? httpUrl(parsed.url) ?? request.url,
160
+ title,
161
+ content: markdown,
162
+ contentType: "text/markdown",
163
+ },
164
+ },
165
+ raw: parsed,
166
+ };
167
+ },
168
+ };
169
+ export const XCRAWL_ADAPTER = xcrawl;
170
+ //# sourceMappingURL=xcrawl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xcrawl.js","sourceRoot":"","sources":["../../src/providers/xcrawl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,175 @@
1
+ import { EnvHttpProxyAgent, fetch as undiciFetch, } from "undici";
2
+ import { WebAccessError } from "../core/errors.js";
3
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
4
+ const SENSITIVE_HEADERS = new Set([
5
+ "authorization",
6
+ "cookie",
7
+ "proxy-authorization",
8
+ "x-api-key",
9
+ "x-subscription-token",
10
+ "x-auth-token",
11
+ "x-access-token",
12
+ ]);
13
+ function isAbortLike(error, signal) {
14
+ if (signal.aborted)
15
+ return true;
16
+ if (!(error instanceof Error))
17
+ return false;
18
+ return (error.name === "AbortError" ||
19
+ error.name === "TimeoutError" ||
20
+ /aborted|timed out|timeout/i.test(error.message));
21
+ }
22
+ function stripSensitiveHeaders(headers) {
23
+ return Object.fromEntries(Object.entries(headers).filter(([name]) => !SENSITIVE_HEADERS.has(name.toLowerCase())));
24
+ }
25
+ function decodeBody(buffer, headers) {
26
+ const contentType = headers.get("content-type") ?? "";
27
+ const charset = contentType.match(/charset\s*=\s*["']?([^;"'\s]+)/i)?.[1] ?? "utf-8";
28
+ try {
29
+ return new TextDecoder(charset).decode(buffer);
30
+ }
31
+ catch {
32
+ return new TextDecoder("utf-8").decode(buffer);
33
+ }
34
+ }
35
+ async function readBody(response, maxBytes, signal) {
36
+ const reader = response.body?.getReader();
37
+ if (!reader) {
38
+ const buffer = new Uint8Array(await response.arrayBuffer());
39
+ if (buffer.byteLength > maxBytes)
40
+ throw new WebAccessError("response_too_large", `响应超过 ${maxBytes} 字节`, { retryable: true });
41
+ return decodeBody(buffer, response.headers);
42
+ }
43
+ const chunks = [];
44
+ let size = 0;
45
+ try {
46
+ while (true) {
47
+ if (signal.aborted)
48
+ throw new WebAccessError("aborted", "请求已取消");
49
+ const { done, value } = await reader.read();
50
+ if (done)
51
+ break;
52
+ if (!value)
53
+ continue;
54
+ size += value.byteLength;
55
+ if (size > maxBytes) {
56
+ await reader.cancel();
57
+ throw new WebAccessError("response_too_large", `响应超过 ${maxBytes} 字节`, { retryable: true });
58
+ }
59
+ chunks.push(value);
60
+ }
61
+ }
62
+ finally {
63
+ reader.releaseLock();
64
+ }
65
+ const buffer = new Uint8Array(size);
66
+ let offset = 0;
67
+ for (const chunk of chunks) {
68
+ buffer.set(chunk, offset);
69
+ offset += chunk.byteLength;
70
+ }
71
+ return decodeBody(buffer, response.headers);
72
+ }
73
+ export function jsonBody(text, provider) {
74
+ try {
75
+ const value = JSON.parse(text);
76
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
77
+ throw new Error("响应 JSON 根节点不是对象");
78
+ }
79
+ return value;
80
+ }
81
+ catch (error) {
82
+ throw new WebAccessError("invalid_response", `${provider} 返回了无效 JSON: ${error instanceof Error ? error.message : String(error)}`);
83
+ }
84
+ }
85
+ export function buildEndpoint(baseUrl, path) {
86
+ const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
87
+ return new URL(path.replace(/^\//, ""), base).toString();
88
+ }
89
+ export class DefaultHttpTransport {
90
+ dispatcher = new EnvHttpProxyAgent();
91
+ async request(rawUrl, options) {
92
+ let current = typeof rawUrl === "string" ? new URL(rawUrl) : new URL(rawUrl.toString());
93
+ if (current.protocol !== "http:" && current.protocol !== "https:")
94
+ throw new WebAccessError("invalid_input", "只能请求 HTTP(S) URL");
95
+ let method = (options.method ?? "GET").toUpperCase();
96
+ let body = options.body;
97
+ let headers = { ...(options.headers ?? {}) };
98
+ const maxRedirects = options.maxRedirects ?? 5;
99
+ for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
100
+ let response;
101
+ try {
102
+ response = await undiciFetch(current, {
103
+ method,
104
+ ...(body !== undefined ? { body } : {}),
105
+ headers,
106
+ signal: options.signal,
107
+ dispatcher: this.dispatcher,
108
+ });
109
+ }
110
+ catch (error) {
111
+ if (isAbortLike(error, options.signal)) {
112
+ throw new WebAccessError(options.signal.aborted ? "aborted" : "timeout", "HTTP 请求超时或已取消", { retryable: options.signal.aborted === false });
113
+ }
114
+ throw new WebAccessError("network_error", error instanceof Error ? error.message : String(error), { retryable: true });
115
+ }
116
+ if (!REDIRECT_STATUSES.has(response.status)) {
117
+ const text = await readBody(response, options.maxResponseBytes, options.signal);
118
+ return {
119
+ status: response.status,
120
+ statusText: response.statusText,
121
+ url: response.url || current.toString(),
122
+ headers: response.headers,
123
+ body: text,
124
+ };
125
+ }
126
+ const location = response.headers.get("location");
127
+ if (!location) {
128
+ const text = await readBody(response, options.maxResponseBytes, options.signal);
129
+ return {
130
+ status: response.status,
131
+ statusText: response.statusText,
132
+ url: response.url || current.toString(),
133
+ headers: response.headers,
134
+ body: text,
135
+ };
136
+ }
137
+ await response.body?.cancel();
138
+ if (redirectCount === maxRedirects) {
139
+ throw new WebAccessError("provider_error", `重定向次数超过 ${maxRedirects}`, { retryable: true, httpStatus: response.status });
140
+ }
141
+ const next = new URL(location, current);
142
+ if (next.protocol !== "http:" && next.protocol !== "https:")
143
+ throw new WebAccessError("provider_error", "重定向目标不是 HTTP(S) URL", { retryable: false });
144
+ if (next.origin !== current.origin)
145
+ headers = stripSensitiveHeaders(headers);
146
+ if (response.status === 303 ||
147
+ ((response.status === 301 || response.status === 302) &&
148
+ method === "POST")) {
149
+ method = "GET";
150
+ body = undefined;
151
+ delete headers["Content-Type"];
152
+ delete headers["content-type"];
153
+ }
154
+ current = next;
155
+ }
156
+ throw new WebAccessError("provider_error", "HTTP 重定向失败", {
157
+ retryable: true,
158
+ });
159
+ }
160
+ }
161
+ export function createAbortSignal(parent, timeoutMs) {
162
+ const timeout = AbortSignal.timeout(Math.max(1, timeoutMs));
163
+ return parent ? AbortSignal.any([parent, timeout]) : timeout;
164
+ }
165
+ export function mergeHeaders(...sources) {
166
+ const result = {};
167
+ for (const source of sources) {
168
+ if (!source)
169
+ continue;
170
+ for (const [name, value] of Object.entries(source))
171
+ result[name] = value;
172
+ }
173
+ return result;
174
+ }
175
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export const VERSION = "0.1.0";
2
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "web-access-cli",
3
+ "version": "0.1.0",
4
+ "description": "Agent-neutral web search and content extraction CLI",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Juexe/web-access-cli.git"
9
+ },
10
+ "homepage": "https://github.com/Juexe/web-access-cli#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/Juexe/web-access-cli/issues"
13
+ },
14
+ "keywords": [
15
+ "cli",
16
+ "web-search",
17
+ "content-extraction",
18
+ "agent"
19
+ ],
20
+ "type": "module",
21
+ "bin": {
22
+ "web-access": "./dist/cli.js"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "schemas",
27
+ "README.md",
28
+ "README_CN.md",
29
+ "LICENSE",
30
+ "THIRD_PARTY_NOTICES.md"
31
+ ],
32
+ "engines": {
33
+ "node": ">=22.19.0"
34
+ },
35
+ "packageManager": "pnpm@11.16.0",
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.build.json && node scripts/write-schemas.mjs",
38
+ "typecheck": "tsc -p tsconfig.json --noEmit",
39
+ "test": "tsx --test test/**/*.test.ts",
40
+ "lint": "biome check .",
41
+ "format": "biome format --write .",
42
+ "check": "pnpm lint && pnpm typecheck && pnpm test && pnpm build",
43
+ "pack:check": "pnpm build && pnpm pack --pack-destination .artifacts"
44
+ },
45
+ "dependencies": {
46
+ "@mozilla/readability": "^0.6.0",
47
+ "commander": "^15.0.0",
48
+ "linkedom": "^0.18.12",
49
+ "open": "^11.0.0",
50
+ "turndown": "^7.2.0",
51
+ "typebox": "^1.3.11",
52
+ "undici": "^8.10.0"
53
+ },
54
+ "devDependencies": {
55
+ "@biomejs/biome": "^2.5.7",
56
+ "@types/node": "^24.0.0",
57
+ "@types/turndown": "^5.0.6",
58
+ "tsx": "^4.20.0",
59
+ "typescript": "^5.9.0"
60
+ }
61
+ }
@@ -0,0 +1,210 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "$schema": {
5
+ "type": "string",
6
+ "format": "uri-reference"
7
+ },
8
+ "providers": {
9
+ "type": "array",
10
+ "items": {
11
+ "anyOf": [
12
+ {
13
+ "type": "object",
14
+ "required": [
15
+ "id",
16
+ "type"
17
+ ],
18
+ "properties": {
19
+ "id": {
20
+ "type": "string",
21
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
22
+ },
23
+ "apiKey": {
24
+ "type": "string"
25
+ },
26
+ "apiKeyEnv": {
27
+ "type": "string",
28
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
29
+ },
30
+ "baseUrl": {
31
+ "type": "string",
32
+ "format": "uri"
33
+ },
34
+ "baseUrlEnv": {
35
+ "type": "string",
36
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
37
+ },
38
+ "headers": {
39
+ "type": "object",
40
+ "patternProperties": {
41
+ "^[^\\r\\n]+$": {
42
+ "type": "string",
43
+ "pattern": "^[^\\r\\n]*$"
44
+ }
45
+ },
46
+ "additionalProperties": false
47
+ },
48
+ "type": {
49
+ "anyOf": [
50
+ {
51
+ "type": "string",
52
+ "const": "tavily"
53
+ },
54
+ {
55
+ "type": "string",
56
+ "const": "exa"
57
+ },
58
+ {
59
+ "type": "string",
60
+ "const": "brave"
61
+ },
62
+ {
63
+ "type": "string",
64
+ "const": "searxng"
65
+ },
66
+ {
67
+ "type": "string",
68
+ "const": "firecrawl"
69
+ },
70
+ {
71
+ "type": "string",
72
+ "const": "jina"
73
+ },
74
+ {
75
+ "type": "string",
76
+ "const": "http"
77
+ }
78
+ ]
79
+ }
80
+ },
81
+ "additionalProperties": false
82
+ },
83
+ {
84
+ "type": "object",
85
+ "required": [
86
+ "id",
87
+ "type"
88
+ ],
89
+ "properties": {
90
+ "id": {
91
+ "type": "string",
92
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
93
+ },
94
+ "apiKey": {
95
+ "type": "string"
96
+ },
97
+ "apiKeyEnv": {
98
+ "type": "string",
99
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
100
+ },
101
+ "baseUrl": {
102
+ "type": "string",
103
+ "format": "uri"
104
+ },
105
+ "baseUrlEnv": {
106
+ "type": "string",
107
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
108
+ },
109
+ "headers": {
110
+ "type": "object",
111
+ "patternProperties": {
112
+ "^[^\\r\\n]+$": {
113
+ "type": "string",
114
+ "pattern": "^[^\\r\\n]*$"
115
+ }
116
+ },
117
+ "additionalProperties": false
118
+ },
119
+ "type": {
120
+ "anyOf": [
121
+ {
122
+ "type": "string",
123
+ "const": "anysearch"
124
+ },
125
+ {
126
+ "type": "string",
127
+ "const": "xcrawl"
128
+ }
129
+ ]
130
+ },
131
+ "searchFilterMode": {
132
+ "anyOf": [
133
+ {
134
+ "type": "string",
135
+ "const": "strict"
136
+ },
137
+ {
138
+ "type": "string",
139
+ "const": "best_effort"
140
+ }
141
+ ]
142
+ }
143
+ },
144
+ "additionalProperties": false
145
+ }
146
+ ]
147
+ }
148
+ },
149
+ "search": {
150
+ "type": "object",
151
+ "properties": {
152
+ "providers": {
153
+ "type": "array",
154
+ "items": {
155
+ "type": "string",
156
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
157
+ }
158
+ },
159
+ "limit": {
160
+ "type": "integer",
161
+ "minimum": 1,
162
+ "maximum": 20
163
+ },
164
+ "timeoutMs": {
165
+ "type": "integer",
166
+ "minimum": 1
167
+ },
168
+ "attemptTimeoutMs": {
169
+ "type": "integer",
170
+ "minimum": 1
171
+ },
172
+ "maxResponseBytes": {
173
+ "type": "integer",
174
+ "minimum": 1
175
+ }
176
+ },
177
+ "additionalProperties": false
178
+ },
179
+ "extract": {
180
+ "type": "object",
181
+ "properties": {
182
+ "providers": {
183
+ "type": "array",
184
+ "items": {
185
+ "type": "string",
186
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
187
+ }
188
+ },
189
+ "timeoutMs": {
190
+ "type": "integer",
191
+ "minimum": 1
192
+ },
193
+ "attemptTimeoutMs": {
194
+ "type": "integer",
195
+ "minimum": 1
196
+ },
197
+ "maxResponseBytes": {
198
+ "type": "integer",
199
+ "minimum": 1
200
+ },
201
+ "minContentCharacters": {
202
+ "type": "integer",
203
+ "minimum": 1
204
+ }
205
+ },
206
+ "additionalProperties": false
207
+ }
208
+ },
209
+ "additionalProperties": false
210
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "type": "object",
3
+ "required": [
4
+ "url",
5
+ "provider"
6
+ ],
7
+ "properties": {
8
+ "url": {
9
+ "type": "string",
10
+ "format": "uri"
11
+ },
12
+ "provider": {
13
+ "type": "string",
14
+ "minLength": 1
15
+ },
16
+ "timeoutMs": {
17
+ "type": "integer",
18
+ "minimum": 1
19
+ }
20
+ }
21
+ }