mcp-scraper 0.69.0 → 0.72.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/CHANGELOG.md +60 -2
- package/README.md +6 -2
- package/dist/{analytics-repository-62CAZAIP.js → analytics-repository-6YLRSWYO.js} +3 -2
- package/dist/bin/api-server.cjs +18592 -12680
- package/dist/bin/api-server.js +4 -4
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +3 -3
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +10492 -9129
- package/dist/bin/mcp-stdio-server.js +9 -7
- package/dist/bin/paa-harvest.cjs +308 -41
- package/dist/bin/paa-harvest.js +4 -3
- package/dist/{chunk-M7D7WO75.js → chunk-2N4V4LVU.js} +3178 -2019
- package/dist/chunk-7RQULQF3.js +263 -0
- package/dist/{chunk-UL4ZKAWZ.js → chunk-A66DGFOU.js} +1 -1
- package/dist/{chunk-ES25GP6C.js → chunk-CXY5WV45.js} +24 -34
- package/dist/{chunk-Y46YNQMM.js → chunk-F5TK4KMT.js} +1 -1
- package/dist/{chunk-62LEXS5O.js → chunk-F6MUGMRN.js} +306 -44
- package/dist/{chunk-5RFQGIYC.js → chunk-FVL4GUTP.js} +2 -2
- package/dist/{chunk-OZIUFN6B.js → chunk-I45JV4EU.js} +2 -2
- package/dist/{chunk-2LXTOAKS.js → chunk-KIPIBPUB.js} +9 -1
- package/dist/chunk-MB72PA6S.js +2003 -0
- package/dist/chunk-OM7HVEJ3.js +26 -0
- package/dist/chunk-PJEEKOUM.js +404 -0
- package/dist/{chunk-RX2QAHML.js → chunk-RAFQEPJ4.js} +2 -2
- package/dist/{chunk-KO5CK5ZT.js → chunk-SR7GSLEA.js} +202 -441
- package/dist/chunk-T3MZISOF.js +240 -0
- package/dist/{chunk-ULYOCJUJ.js → chunk-TUTQHP4O.js} +1 -1
- package/dist/{chunk-65FTMB7G.js → chunk-WEFPBAAG.js} +180 -9
- package/dist/{chunk-LN6N3YLK.js → chunk-WFQ2E4WE.js} +1 -1
- package/dist/{db-ZGZAKYBW.js → db-566MOHHD.js} +7 -1
- package/dist/{extract-bundle-SXSJCPQI.js → extract-bundle-337ZDIIQ.js} +4 -4
- package/dist/gmail-service-E276SBJU.js +25 -0
- package/dist/index.cjs +322 -49
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +4 -3
- package/dist/{lead-list-enrichment-repository-CXLVIV3R.js → lead-list-enrichment-repository-WWEMJ7EN.js} +2 -2
- package/dist/{location-data-repository-G72M7DTN.js → location-data-repository-H4B2BWGY.js} +2 -2
- package/dist/{server-WCNYXILA.js → server-UGWC5YMD.js} +8376 -6616
- package/dist/{site-extract-repository-RLB3TFJ3.js → site-extract-repository-ACNAVNDN.js} +3 -3
- package/dist/{worker-KHSJG365.js → worker-JQORPCFQ.js} +9 -7
- package/package.json +1 -1
- package/dist/chunk-2L4C4DAZ.js +0 -103
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import {
|
|
2
|
+
publicErrorMessage,
|
|
3
|
+
sanitizeVendorName
|
|
4
|
+
} from "./chunk-WEFPBAAG.js";
|
|
5
|
+
|
|
6
|
+
// src/api/outbound-sanitize.ts
|
|
7
|
+
var KEY_RENAMES = {
|
|
8
|
+
kernel: "browserRuntime"
|
|
9
|
+
};
|
|
10
|
+
var ERROR_VALUE_KEYS = /error|message/i;
|
|
11
|
+
var PRIVATE_UPSTREAM_FAILURE = /(?:spending|billing|organization|account).{0,80}(?:cap|limit|blocked|disabled)|(?:quota|capacity).{0,40}(?:reached|exceeded)|https?:\/\/\S*(?:dashboard|onkernel)/i;
|
|
12
|
+
var PRIVATE_RUNTIME_FAILURE = /\b(?:ENOENT|ENOTDIR|EACCES|EPERM|EISDIR|EMFILE|ENFILE)\b|\b(?:mkdir|open|stat|lstat|readFile|writeFile)\s+['"]?(?:\/|[A-Za-z]:\\)|(?:^|[\s'"])(?:\/Users|\/home|\/tmp|\/var|\/private|\/opt|\/srv|\/root)\//i;
|
|
13
|
+
var INTERNAL_DIAGNOSTIC_KEYS = /* @__PURE__ */ new Set([
|
|
14
|
+
"kernel_session_id",
|
|
15
|
+
"browser_session_id",
|
|
16
|
+
"kernelSessionId",
|
|
17
|
+
"browserSessionId",
|
|
18
|
+
"sessionId",
|
|
19
|
+
"kernel_delete_started",
|
|
20
|
+
"session_cleanup_started",
|
|
21
|
+
"kernelDeleteStarted",
|
|
22
|
+
"sessionCleanupStarted",
|
|
23
|
+
"kernel_delete_succeeded",
|
|
24
|
+
"session_cleanup_succeeded",
|
|
25
|
+
"kernelDeleteSucceeded",
|
|
26
|
+
"sessionCleanupSucceeded",
|
|
27
|
+
"kernel_delete_error",
|
|
28
|
+
"session_cleanup_error",
|
|
29
|
+
"kernelDeleteError",
|
|
30
|
+
"sessionCleanupError",
|
|
31
|
+
"kernelProxyId",
|
|
32
|
+
"proxyId",
|
|
33
|
+
"requestedProxyIdSuffix",
|
|
34
|
+
"retrievedProxyIdSuffix",
|
|
35
|
+
"provider",
|
|
36
|
+
"providerName",
|
|
37
|
+
"service",
|
|
38
|
+
"serviceName",
|
|
39
|
+
"vendor",
|
|
40
|
+
"vendorName",
|
|
41
|
+
"organization",
|
|
42
|
+
"organizationId",
|
|
43
|
+
"accountId",
|
|
44
|
+
// Provider attempt telemetry is projected field-by-field by sanitizeAttempts.
|
|
45
|
+
// Keeping these keys private here prevents an unreviewed nested object from
|
|
46
|
+
// bypassing that projection through the generic diagnostics sanitizer.
|
|
47
|
+
"browser_provider",
|
|
48
|
+
"provider_session_id",
|
|
49
|
+
"provider_lookup_status",
|
|
50
|
+
"provider_status",
|
|
51
|
+
"provider_error_code",
|
|
52
|
+
"provider_error_message",
|
|
53
|
+
"provider_reason_source",
|
|
54
|
+
"provider_duration_ms",
|
|
55
|
+
"provider_bandwidth_bytes",
|
|
56
|
+
"provider_captcha",
|
|
57
|
+
"provider_checked_at",
|
|
58
|
+
"provider_detail",
|
|
59
|
+
"provider_detail_json",
|
|
60
|
+
"provider_disconnect_observed",
|
|
61
|
+
"provider_disconnect_message",
|
|
62
|
+
"browserProvider",
|
|
63
|
+
"providerSessionId",
|
|
64
|
+
"providerLookupStatus",
|
|
65
|
+
"providerStatus",
|
|
66
|
+
"providerErrorCode",
|
|
67
|
+
"providerErrorMessage",
|
|
68
|
+
"providerReasonSource",
|
|
69
|
+
"providerDurationMs",
|
|
70
|
+
"providerBandwidthBytes",
|
|
71
|
+
"providerCaptcha",
|
|
72
|
+
"providerCheckedAt",
|
|
73
|
+
"providerDetail",
|
|
74
|
+
"providerDisconnectObserved",
|
|
75
|
+
"providerDisconnectMessage"
|
|
76
|
+
]);
|
|
77
|
+
var VENDOR_URL_KEYS = /* @__PURE__ */ new Set([
|
|
78
|
+
"hosted_url",
|
|
79
|
+
"hostedUrl",
|
|
80
|
+
"live_view_url",
|
|
81
|
+
"liveViewUrl",
|
|
82
|
+
"cdp_ws_url",
|
|
83
|
+
"cdpWsUrl",
|
|
84
|
+
"browser_live_view_url"
|
|
85
|
+
]);
|
|
86
|
+
var VENDOR_URL_RE = /\b(?:wss?|https?):\/\/[^\s"'<>]*\bonkernel\.com[^\s"'<>]*/gi;
|
|
87
|
+
function redactVendorUrls(value) {
|
|
88
|
+
return value.replace(VENDOR_URL_RE, "[browser-service]");
|
|
89
|
+
}
|
|
90
|
+
var PUBLIC_BROWSER_PROVIDERS = /* @__PURE__ */ new Set(["bright_data_browser_api", "kernel", "local"]);
|
|
91
|
+
var PUBLIC_PROVIDER_LOOKUP_STATUSES = /* @__PURE__ */ new Set([
|
|
92
|
+
"pending",
|
|
93
|
+
"complete",
|
|
94
|
+
"not_found",
|
|
95
|
+
"unavailable_credentials",
|
|
96
|
+
"temporary_error",
|
|
97
|
+
"invalid_payload",
|
|
98
|
+
"not_applicable"
|
|
99
|
+
]);
|
|
100
|
+
var PUBLIC_PROVIDER_STATUSES = /* @__PURE__ */ new Set([
|
|
101
|
+
"active",
|
|
102
|
+
"running",
|
|
103
|
+
"complete",
|
|
104
|
+
"completed",
|
|
105
|
+
"failed",
|
|
106
|
+
"closed",
|
|
107
|
+
"stopped",
|
|
108
|
+
"terminated",
|
|
109
|
+
"timed_out"
|
|
110
|
+
]);
|
|
111
|
+
var PUBLIC_PROVIDER_REASON_SOURCES = /* @__PURE__ */ new Set([
|
|
112
|
+
"provider_session_api",
|
|
113
|
+
"client_runtime",
|
|
114
|
+
"extractor",
|
|
115
|
+
"unknown"
|
|
116
|
+
]);
|
|
117
|
+
var PUBLIC_PROVIDER_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
118
|
+
"browser_disconnected",
|
|
119
|
+
"worker_disconnect",
|
|
120
|
+
"job_killed",
|
|
121
|
+
"cdp_cmd_timeout",
|
|
122
|
+
"network_inactivity_timeout",
|
|
123
|
+
"session_timeout",
|
|
124
|
+
"client_timeout",
|
|
125
|
+
"navigate_domains_limit",
|
|
126
|
+
"cdp_error",
|
|
127
|
+
"browser_session_interrupted",
|
|
128
|
+
"provider_detail_pending",
|
|
129
|
+
"provider_lookup_unavailable",
|
|
130
|
+
"provider_reported_no_error",
|
|
131
|
+
"provider_session_not_found",
|
|
132
|
+
"provider_invalid_json",
|
|
133
|
+
"provider_invalid_payload",
|
|
134
|
+
"provider_lookup_timeout",
|
|
135
|
+
"provider_lookup_network_error",
|
|
136
|
+
"unknown"
|
|
137
|
+
]);
|
|
138
|
+
var PROVIDER_TELEMETRY_KEYS = /* @__PURE__ */ new Set([
|
|
139
|
+
"browser_provider",
|
|
140
|
+
"provider_session_id",
|
|
141
|
+
"provider_lookup_status",
|
|
142
|
+
"provider_status",
|
|
143
|
+
"provider_error_code",
|
|
144
|
+
"provider_error_message",
|
|
145
|
+
"provider_reason_source",
|
|
146
|
+
"provider_duration_ms",
|
|
147
|
+
"provider_bandwidth_bytes",
|
|
148
|
+
"provider_captcha",
|
|
149
|
+
"provider_checked_at",
|
|
150
|
+
"provider_detail",
|
|
151
|
+
"provider_detail_json",
|
|
152
|
+
"provider_disconnect_observed",
|
|
153
|
+
"provider_disconnect_message"
|
|
154
|
+
]);
|
|
155
|
+
var MAX_PROVIDER_SESSION_ID_LENGTH = 512;
|
|
156
|
+
var MAX_PROVIDER_MESSAGE_LENGTH = 320;
|
|
157
|
+
function allowlistedString(value, values) {
|
|
158
|
+
return typeof value === "string" && values.has(value) ? value : null;
|
|
159
|
+
}
|
|
160
|
+
function publicProviderErrorCode(value) {
|
|
161
|
+
if (typeof value !== "string") return null;
|
|
162
|
+
if (PUBLIC_PROVIDER_ERROR_CODES.has(value)) return value;
|
|
163
|
+
return /^provider_http_(?:429|5\d\d)$/.test(value) ? value : null;
|
|
164
|
+
}
|
|
165
|
+
function publicProviderSessionId(value) {
|
|
166
|
+
if (typeof value !== "string") return null;
|
|
167
|
+
if (value.length < 1 || value.length > MAX_PROVIDER_SESSION_ID_LENGTH) return null;
|
|
168
|
+
if (/^(?:authorization|bearer|password|secret|token|api[_-]?key|account)/i.test(value)) return null;
|
|
169
|
+
return /^[A-Za-z0-9._:-]+$/.test(value) && !value.includes("://") ? value : null;
|
|
170
|
+
}
|
|
171
|
+
function publicNonNegativeInteger(value) {
|
|
172
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
173
|
+
}
|
|
174
|
+
function publicIsoTimestamp(value) {
|
|
175
|
+
if (typeof value !== "string" || value.length > 40) return null;
|
|
176
|
+
const parsed = Date.parse(value);
|
|
177
|
+
return Number.isFinite(parsed) && new Date(parsed).toISOString() === value ? value : null;
|
|
178
|
+
}
|
|
179
|
+
function publicProviderMessage(value) {
|
|
180
|
+
if (typeof value !== "string") return null;
|
|
181
|
+
const normalized = value.replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim();
|
|
182
|
+
if (!normalized || normalized.startsWith("{") || normalized.startsWith("[")) return null;
|
|
183
|
+
const redacted = normalized.replace(/\b(?:wss?|https?):\/\/\S+/gi, "[redacted endpoint]").replace(/\b(?:authorization|proxy-authorization)\s*:\s*(?:Bearer\s+)?\S+/gi, "[redacted credential]").replace(/\bBearer\s+\S+/gi, "[redacted credential]").replace(/\b(?:api[_-]?key|password|secret|token|account[_-]?id)\s*[=:]\s*[^\s,;]+/gi, "[redacted credential]").replace(/\b(?:account|organization)\s+(?:id\s+)?[A-Za-z0-9_-]{4,}/gi, "[redacted account]");
|
|
184
|
+
return redactVendorUrls(redacted).slice(0, MAX_PROVIDER_MESSAGE_LENGTH);
|
|
185
|
+
}
|
|
186
|
+
function publicNullableBoolean(value) {
|
|
187
|
+
return typeof value === "boolean" ? value : null;
|
|
188
|
+
}
|
|
189
|
+
function projectAttemptProviderTelemetry(attempt) {
|
|
190
|
+
return {
|
|
191
|
+
browser_provider: allowlistedString(attempt.browser_provider, PUBLIC_BROWSER_PROVIDERS),
|
|
192
|
+
provider_session_id: publicProviderSessionId(attempt.provider_session_id),
|
|
193
|
+
provider_lookup_status: allowlistedString(attempt.provider_lookup_status, PUBLIC_PROVIDER_LOOKUP_STATUSES),
|
|
194
|
+
provider_status: allowlistedString(attempt.provider_status, PUBLIC_PROVIDER_STATUSES),
|
|
195
|
+
provider_error_code: publicProviderErrorCode(attempt.provider_error_code),
|
|
196
|
+
provider_error_message: publicProviderMessage(attempt.provider_error_message),
|
|
197
|
+
provider_reason_source: allowlistedString(attempt.provider_reason_source, PUBLIC_PROVIDER_REASON_SOURCES),
|
|
198
|
+
provider_duration_ms: publicNonNegativeInteger(attempt.provider_duration_ms),
|
|
199
|
+
provider_bandwidth_bytes: publicNonNegativeInteger(attempt.provider_bandwidth_bytes),
|
|
200
|
+
provider_captcha: publicNullableBoolean(attempt.provider_captcha),
|
|
201
|
+
provider_checked_at: publicIsoTimestamp(attempt.provider_checked_at),
|
|
202
|
+
provider_disconnect_observed: publicNullableBoolean(attempt.provider_disconnect_observed),
|
|
203
|
+
provider_disconnect_message: publicProviderMessage(attempt.provider_disconnect_message)
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function sanitizeOutboundDiagnostics(value, parentKey = "") {
|
|
207
|
+
if (typeof value === "string") {
|
|
208
|
+
let out = redactVendorUrls(value);
|
|
209
|
+
if (ERROR_VALUE_KEYS.test(parentKey) && (PRIVATE_UPSTREAM_FAILURE.test(value) || PRIVATE_RUNTIME_FAILURE.test(value))) {
|
|
210
|
+
out = publicErrorMessage("service_unavailable");
|
|
211
|
+
} else if (ERROR_VALUE_KEYS.test(parentKey)) {
|
|
212
|
+
out = sanitizeVendorName(out);
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
if (Array.isArray(value)) return value.map((v) => sanitizeOutboundDiagnostics(v, parentKey));
|
|
217
|
+
if (value !== null && typeof value === "object") {
|
|
218
|
+
const out = {};
|
|
219
|
+
for (const [key, val] of Object.entries(value)) {
|
|
220
|
+
if (INTERNAL_DIAGNOSTIC_KEYS.has(key)) continue;
|
|
221
|
+
const renamed = KEY_RENAMES[key] ?? key;
|
|
222
|
+
if (VENDOR_URL_KEYS.has(key)) {
|
|
223
|
+
out[renamed] = null;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
out[renamed] = sanitizeOutboundDiagnostics(val, key);
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
230
|
+
return value;
|
|
231
|
+
}
|
|
232
|
+
function sanitizeAttempts(attempts) {
|
|
233
|
+
return attempts.map((attempt) => {
|
|
234
|
+
if (attempt === null || typeof attempt !== "object" || Array.isArray(attempt)) {
|
|
235
|
+
return sanitizeOutboundDiagnostics(attempt);
|
|
236
|
+
}
|
|
237
|
+
const row = attempt;
|
|
238
|
+
const sanitized = sanitizeOutboundDiagnostics(row);
|
|
239
|
+
const hasProviderTelemetry = Object.keys(row).some((key) => PROVIDER_TELEMETRY_KEYS.has(key));
|
|
240
|
+
if (!hasProviderTelemetry) return sanitized;
|
|
241
|
+
return {
|
|
242
|
+
...sanitized,
|
|
243
|
+
...projectAttemptProviderTelemetry(row)
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function sanitizeHarvestResult(result) {
|
|
248
|
+
const diagnostics = result?.diagnostics;
|
|
249
|
+
if (!diagnostics?.debug) return result;
|
|
250
|
+
return {
|
|
251
|
+
...result,
|
|
252
|
+
diagnostics: {
|
|
253
|
+
...diagnostics,
|
|
254
|
+
debug: sanitizeOutboundDiagnostics(diagnostics.debug)
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export {
|
|
260
|
+
sanitizeOutboundDiagnostics,
|
|
261
|
+
sanitizeAttempts,
|
|
262
|
+
sanitizeHarvestResult
|
|
263
|
+
};
|
|
@@ -1,26 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getDb
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
|
|
5
|
-
// src/lib/browser-service-env.ts
|
|
6
|
-
function browserServiceApiKey() {
|
|
7
|
-
const value = (process.env.BROWSER_SERVICE_API_KEY ?? process.env.KERNEL_API_KEY)?.trim();
|
|
8
|
-
return value || void 0;
|
|
9
|
-
}
|
|
10
|
-
function browserServiceProxyId() {
|
|
11
|
-
return void 0;
|
|
12
|
-
}
|
|
13
|
-
function browserServiceProfileName() {
|
|
14
|
-
const value = (process.env.BROWSER_AGENT_PROFILE_NAME ?? process.env.BROWSER_SERVICE_PROFILE_NAME ?? process.env.KERNEL_BROWSER_PROFILE_NAME ?? process.env.KERNEL_PROFILE_NAME)?.trim();
|
|
15
|
-
return value || void 0;
|
|
16
|
-
}
|
|
17
|
-
function browserServiceProfileSaveChanges() {
|
|
18
|
-
const value = (process.env.BROWSER_AGENT_PROFILE_SAVE_CHANGES ?? process.env.BROWSER_SERVICE_PROFILE_SAVE_CHANGES ?? process.env.KERNEL_BROWSER_PROFILE_SAVE_CHANGES ?? process.env.KERNEL_PROFILE_SAVE_CHANGES)?.trim().toLowerCase();
|
|
19
|
-
if (!value) return void 0;
|
|
20
|
-
if (["1", "true", "yes", "on"].includes(value)) return true;
|
|
21
|
-
if (["0", "false", "no", "off"].includes(value)) return false;
|
|
22
|
-
return void 0;
|
|
23
|
-
}
|
|
3
|
+
} from "./chunk-WEFPBAAG.js";
|
|
24
4
|
|
|
25
5
|
// src/api/cost-context.ts
|
|
26
6
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -53,6 +33,7 @@ var NANGO_USD_PER_CONNECTION_MONTH = envRate("NANGO_USD_PER_CONNECTION_MONTH", 1
|
|
|
53
33
|
var NANGO_USD_PER_FUNCTION_RUN = envRate("NANGO_USD_PER_FUNCTION_RUN", 1e-4);
|
|
54
34
|
var NANGO_USD_PER_PROXY_REQUEST = envRate("NANGO_USD_PER_PROXY_REQUEST", 1e-4);
|
|
55
35
|
var NANGO_USD_PER_COMPUTE_SEC = envRate("NANGO_USD_PER_COMPUTE_SEC", 2e-4);
|
|
36
|
+
var BRIGHTDATA_BROWSER_USD_PER_GB = envRate("BRIGHTDATA_BROWSER_USD_PER_GB", 0);
|
|
56
37
|
function kernelCostUsd(ms, headful) {
|
|
57
38
|
const sec = Math.max(0, ms) / 1e3;
|
|
58
39
|
return sec * (headful ? KERNEL_HEADFUL_USD_PER_SEC : KERNEL_HEADLESS_USD_PER_SEC);
|
|
@@ -70,6 +51,9 @@ function vendorCostUsd(vendor, units) {
|
|
|
70
51
|
if (vendor === "nango_function_run") return Math.max(0, units) * NANGO_USD_PER_FUNCTION_RUN;
|
|
71
52
|
if (vendor === "nango_proxy_request") return Math.max(0, units) * NANGO_USD_PER_PROXY_REQUEST;
|
|
72
53
|
if (vendor === "nango_compute") return Math.max(0, units) * NANGO_USD_PER_COMPUTE_SEC;
|
|
54
|
+
if (vendor === "brightdata_browser_api") {
|
|
55
|
+
return Math.max(0, units) / 1e9 * BRIGHTDATA_BROWSER_USD_PER_GB;
|
|
56
|
+
}
|
|
73
57
|
return 0;
|
|
74
58
|
}
|
|
75
59
|
|
|
@@ -90,7 +74,8 @@ async function runCostTelemetryMigration() {
|
|
|
90
74
|
SELECT
|
|
91
75
|
(SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name IN ('kernel_session_log', 'vendor_usage_log', 'cost_probe_runs')) = 3
|
|
92
76
|
AND (SELECT COUNT(*) FROM pragma_table_info('kernel_session_log') WHERE name IN ('proxy_source', 'proxy_type', 'method')) = 3
|
|
93
|
-
AND (SELECT COUNT(*) FROM pragma_table_info('vendor_usage_log') WHERE name
|
|
77
|
+
AND (SELECT COUNT(*) FROM pragma_table_info('vendor_usage_log') WHERE name IN ('method', 'source_key')) = 2
|
|
78
|
+
AND (SELECT COUNT(*) FROM sqlite_master WHERE type = 'index' AND name = 'vendor_usage_log_vendor_source_key') = 1
|
|
94
79
|
AND (SELECT COUNT(*) FROM pragma_table_info('cost_probe_runs') WHERE name IN ('units', 'unit_type', 'mode')) = 3
|
|
95
80
|
AS ready
|
|
96
81
|
`);
|
|
@@ -146,6 +131,7 @@ async function runCostTelemetryMigration() {
|
|
|
146
131
|
unit_type TEXT,
|
|
147
132
|
est_cost_usd REAL NOT NULL DEFAULT 0,
|
|
148
133
|
error TEXT,
|
|
134
|
+
source_key TEXT,
|
|
149
135
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
150
136
|
)
|
|
151
137
|
`);
|
|
@@ -156,6 +142,11 @@ async function runCostTelemetryMigration() {
|
|
|
156
142
|
await db.execute(`ALTER TABLE vendor_usage_log ADD COLUMN method TEXT`);
|
|
157
143
|
} catch {
|
|
158
144
|
}
|
|
145
|
+
try {
|
|
146
|
+
await db.execute(`ALTER TABLE vendor_usage_log ADD COLUMN source_key TEXT`);
|
|
147
|
+
} catch {
|
|
148
|
+
}
|
|
149
|
+
await db.execute(`CREATE UNIQUE INDEX IF NOT EXISTS vendor_usage_log_vendor_source_key ON vendor_usage_log(vendor, source_key) WHERE source_key IS NOT NULL`);
|
|
159
150
|
await db.execute(`
|
|
160
151
|
CREATE TABLE IF NOT EXISTS cost_probe_runs (
|
|
161
152
|
id TEXT PRIMARY KEY,
|
|
@@ -235,26 +226,29 @@ async function recordVendorUsage(r) {
|
|
|
235
226
|
await migrateCostTelemetry();
|
|
236
227
|
const ctx = currentCostContext();
|
|
237
228
|
const db = getDb();
|
|
238
|
-
await db.execute({
|
|
239
|
-
sql: `INSERT INTO vendor_usage_log
|
|
240
|
-
(id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method)
|
|
241
|
-
VALUES (
|
|
229
|
+
const result = await db.execute({
|
|
230
|
+
sql: `INSERT OR IGNORE INTO vendor_usage_log
|
|
231
|
+
(id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method, source_key)
|
|
232
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)`,
|
|
242
233
|
args: [
|
|
243
234
|
randomUUID(),
|
|
244
|
-
ctx?.op ?? null,
|
|
245
|
-
ctx?.probeRunId ?? null,
|
|
246
|
-
ctx?.userId ?? null,
|
|
235
|
+
r.op ?? ctx?.op ?? null,
|
|
236
|
+
r.probeRunId ?? ctx?.probeRunId ?? null,
|
|
237
|
+
r.userId ?? ctx?.userId ?? null,
|
|
247
238
|
r.vendor,
|
|
248
239
|
r.model ?? null,
|
|
249
240
|
r.units,
|
|
250
241
|
r.unitType,
|
|
251
242
|
vendorCostUsd(r.vendor, r.units),
|
|
252
243
|
r.error ?? null,
|
|
253
|
-
ctx?.subOp ?? null
|
|
244
|
+
r.method ?? ctx?.subOp ?? null,
|
|
245
|
+
r.sourceKey ?? null
|
|
254
246
|
]
|
|
255
247
|
});
|
|
248
|
+
return result.rowsAffected === 1;
|
|
256
249
|
} catch (err) {
|
|
257
250
|
console.warn("[cost-telemetry] recordVendorUsage failed:", err instanceof Error ? err.message : String(err));
|
|
251
|
+
return false;
|
|
258
252
|
}
|
|
259
253
|
}
|
|
260
254
|
function boolToInt(v) {
|
|
@@ -263,10 +257,6 @@ function boolToInt(v) {
|
|
|
263
257
|
}
|
|
264
258
|
|
|
265
259
|
export {
|
|
266
|
-
browserServiceApiKey,
|
|
267
|
-
browserServiceProxyId,
|
|
268
|
-
browserServiceProfileName,
|
|
269
|
-
browserServiceProfileSaveChanges,
|
|
270
260
|
HEADLESS_HARVEST_TEST_ENV,
|
|
271
261
|
runWithCostContext,
|
|
272
262
|
currentCostContext,
|