mcp-scraper 0.66.5 → 0.66.7
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 +17 -1
- package/README.md +1 -1
- package/dist/bin/api-server.cjs +910 -601
- package/dist/bin/api-server.js +3 -3
- 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 +2 -2
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +105 -18
- package/dist/bin/mcp-stdio-server.js +6 -6
- package/dist/bin/paa-harvest.cjs +14 -1
- package/dist/bin/paa-harvest.js +3 -3
- package/dist/{chunk-RSFMR7O7.js → chunk-7KB5QTHP.js} +1 -1
- package/dist/{chunk-K7Y27ND3.js → chunk-CGOMGGOF.js} +2 -2
- package/dist/{chunk-DBWWIK7O.js → chunk-EVOBJYBE.js} +1 -1
- package/dist/{chunk-3EYALCYK.js → chunk-F434YJPV.js} +1 -1
- package/dist/{chunk-PMCT2YQM.js → chunk-HBZENASD.js} +1 -1
- package/dist/{chunk-KXRWY7DZ.js → chunk-HWGQVP3Q.js} +1 -1
- package/dist/{chunk-55B3T5L2.js → chunk-HZDJ5UZ4.js} +68 -1
- package/dist/{chunk-ABYBPODM.js → chunk-JZPSG4NR.js} +1 -1
- package/dist/{chunk-CETDPNMZ.js → chunk-LVXRWJJJ.js} +1 -1
- package/dist/{chunk-TCOP5BT7.js → chunk-O7ZC5Y3Z.js} +1 -1
- package/dist/{chunk-3TKKJQB4.js → chunk-U2UHJWFW.js} +1 -1
- package/dist/{chunk-OJFWURGD.js → chunk-Z5QQEWXA.js} +53 -19
- package/dist/{db-4RVZ3NYZ.js → db-MNNNIWVS.js} +1 -1
- package/dist/{extract-bundle-EA5URLXN.js → extract-bundle-RW7CVIRF.js} +3 -3
- package/dist/index.cjs +14 -1
- package/dist/index.js +3 -3
- package/dist/{lead-list-enrichment-repository-IBXNWM6H.js → lead-list-enrichment-repository-PZYE6TDP.js} +2 -2
- package/dist/{location-data-repository-WHHQUCUI.js → location-data-repository-EPCNGMOM.js} +2 -2
- package/dist/{server-LESUYFDI.js → server-KSVJ4X4V.js} +650 -445
- package/dist/{site-extract-repository-NTM4MDQN.js → site-extract-repository-CZ7SVT3Z.js} +2 -2
- package/dist/{worker-UTBUWEXQ.js → worker-IBLGV272.js} +5 -5
- package/package.json +1 -1
package/dist/bin/api-server.cjs
CHANGED
|
@@ -164,6 +164,20 @@ function publicErrorType(code) {
|
|
|
164
164
|
case "site_export_read_failed":
|
|
165
165
|
case "site_export_image_not_found":
|
|
166
166
|
return "extraction";
|
|
167
|
+
case "image_url_invalid":
|
|
168
|
+
case "image_url_not_https":
|
|
169
|
+
case "image_host_unresolvable":
|
|
170
|
+
case "image_host_blocked":
|
|
171
|
+
case "image_redirect_invalid":
|
|
172
|
+
case "image_source_unavailable":
|
|
173
|
+
case "image_too_large":
|
|
174
|
+
case "image_redirect_limit":
|
|
175
|
+
case "image_base64_invalid":
|
|
176
|
+
case "image_source_missing":
|
|
177
|
+
case "image_format_unsupported":
|
|
178
|
+
case "image_storage_unconfigured":
|
|
179
|
+
case "featured_image_unhostable":
|
|
180
|
+
return "invalid_request";
|
|
167
181
|
case "insufficient_balance":
|
|
168
182
|
return "billing";
|
|
169
183
|
case "vendor_unavailable":
|
|
@@ -237,6 +251,32 @@ function publicErrorMessage(code) {
|
|
|
237
251
|
return "The stored site export could not be read or did not pass its integrity check.";
|
|
238
252
|
case "site_export_image_not_found":
|
|
239
253
|
return "The requested site-export image was not found, expired, or does not belong to this account.";
|
|
254
|
+
case "image_url_invalid":
|
|
255
|
+
return "The image source is not a valid URL. Use a stable public HTTPS URL or inline image bytes.";
|
|
256
|
+
case "image_url_not_https":
|
|
257
|
+
return "Commons image sources must use a public HTTPS URL or inline image bytes.";
|
|
258
|
+
case "image_host_unresolvable":
|
|
259
|
+
return "The image host could not be resolved. Use a different stable public URL or inline image bytes.";
|
|
260
|
+
case "image_host_blocked":
|
|
261
|
+
return "The image source resolves to a network address Commons cannot fetch safely.";
|
|
262
|
+
case "image_redirect_invalid":
|
|
263
|
+
return "The image source redirected to an invalid or unsafe destination.";
|
|
264
|
+
case "image_source_unavailable":
|
|
265
|
+
return "The image source could not be fetched. Host a different stable public URL or provide inline image bytes.";
|
|
266
|
+
case "image_too_large":
|
|
267
|
+
return "The image exceeds the Commons image size limit.";
|
|
268
|
+
case "image_redirect_limit":
|
|
269
|
+
return "The image source exceeded the Commons redirect limit.";
|
|
270
|
+
case "image_base64_invalid":
|
|
271
|
+
return "The supplied inline image bytes are invalid.";
|
|
272
|
+
case "image_source_missing":
|
|
273
|
+
return "Provide either a stable public image URL or inline image bytes.";
|
|
274
|
+
case "image_format_unsupported":
|
|
275
|
+
return "Commons accepts JPEG, PNG, GIF, or WebP image bytes.";
|
|
276
|
+
case "image_storage_unconfigured":
|
|
277
|
+
return "Commons image storage is temporarily unavailable.";
|
|
278
|
+
case "featured_image_unhostable":
|
|
279
|
+
return "The required featured image could not be hosted for Commons publication.";
|
|
240
280
|
default:
|
|
241
281
|
return PUBLIC_SERVICE_UNAVAILABLE_MESSAGE;
|
|
242
282
|
}
|
|
@@ -299,7 +339,20 @@ var init_errors = __esm({
|
|
|
299
339
|
"site_export_not_found",
|
|
300
340
|
"site_export_format_unavailable",
|
|
301
341
|
"site_export_read_failed",
|
|
302
|
-
"site_export_image_not_found"
|
|
342
|
+
"site_export_image_not_found",
|
|
343
|
+
"image_url_invalid",
|
|
344
|
+
"image_url_not_https",
|
|
345
|
+
"image_host_unresolvable",
|
|
346
|
+
"image_host_blocked",
|
|
347
|
+
"image_redirect_invalid",
|
|
348
|
+
"image_source_unavailable",
|
|
349
|
+
"image_too_large",
|
|
350
|
+
"image_redirect_limit",
|
|
351
|
+
"image_base64_invalid",
|
|
352
|
+
"image_source_missing",
|
|
353
|
+
"image_format_unsupported",
|
|
354
|
+
"image_storage_unconfigured",
|
|
355
|
+
"featured_image_unhostable"
|
|
303
356
|
];
|
|
304
357
|
PUBLIC_ERROR_TYPES = [
|
|
305
358
|
"request_aborted",
|
|
@@ -4495,6 +4548,20 @@ async function migrate(options = {}) {
|
|
|
4495
4548
|
PRIMARY KEY (user_id, connection_id, period_start)
|
|
4496
4549
|
)
|
|
4497
4550
|
`);
|
|
4551
|
+
await db.execute(`
|
|
4552
|
+
CREATE TABLE IF NOT EXISTS connected_account_charge_transfers (
|
|
4553
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4554
|
+
user_id INTEGER NOT NULL,
|
|
4555
|
+
period_start TEXT NOT NULL,
|
|
4556
|
+
from_connection_id TEXT NOT NULL,
|
|
4557
|
+
to_connection_id TEXT NOT NULL,
|
|
4558
|
+
provider_config_key TEXT NOT NULL,
|
|
4559
|
+
transferred_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
4560
|
+
UNIQUE (user_id, period_start, from_connection_id),
|
|
4561
|
+
CHECK (from_connection_id <> to_connection_id)
|
|
4562
|
+
)
|
|
4563
|
+
`);
|
|
4564
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS connected_account_charge_transfers_destination ON connected_account_charge_transfers(user_id, period_start, to_connection_id, transferred_at DESC)`);
|
|
4498
4565
|
await db.execute(`
|
|
4499
4566
|
CREATE TABLE IF NOT EXISTS billing_credits (
|
|
4500
4567
|
idempotency_key TEXT PRIMARY KEY,
|
|
@@ -36288,6 +36355,357 @@ var init_subscription_status_policy = __esm({
|
|
|
36288
36355
|
}
|
|
36289
36356
|
});
|
|
36290
36357
|
|
|
36358
|
+
// src/api/service-connections.ts
|
|
36359
|
+
function ensureServiceConnectionsSchema() {
|
|
36360
|
+
const currentDb = getDb();
|
|
36361
|
+
if (schemaReady && schemaDb5 === currentDb) return schemaReady;
|
|
36362
|
+
schemaDb5 = currentDb;
|
|
36363
|
+
schemaReady = (async () => {
|
|
36364
|
+
const db = currentDb;
|
|
36365
|
+
await db.execute(`
|
|
36366
|
+
CREATE TABLE IF NOT EXISTS service_connections (
|
|
36367
|
+
id TEXT PRIMARY KEY,
|
|
36368
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
36369
|
+
provider_config_key TEXT NOT NULL,
|
|
36370
|
+
provider TEXT,
|
|
36371
|
+
transport TEXT NOT NULL,
|
|
36372
|
+
upstream_connection_id TEXT,
|
|
36373
|
+
label TEXT,
|
|
36374
|
+
user_label TEXT,
|
|
36375
|
+
provider_account_id TEXT,
|
|
36376
|
+
provider_account_email TEXT,
|
|
36377
|
+
provider_account_name TEXT,
|
|
36378
|
+
provider_identity_checked_at TEXT,
|
|
36379
|
+
provider_identity_source_updated_at TEXT,
|
|
36380
|
+
lifecycle_status TEXT NOT NULL DEFAULT 'pending',
|
|
36381
|
+
operational_status TEXT NOT NULL DEFAULT 'unknown',
|
|
36382
|
+
reconnect_required INTEGER NOT NULL DEFAULT 0,
|
|
36383
|
+
actions_enabled INTEGER NOT NULL DEFAULT 0,
|
|
36384
|
+
read_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
36385
|
+
action_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
36386
|
+
tool_revision TEXT,
|
|
36387
|
+
last_checked_at TEXT,
|
|
36388
|
+
last_successful_call_at TEXT,
|
|
36389
|
+
last_failure_at TEXT,
|
|
36390
|
+
last_failure_code TEXT,
|
|
36391
|
+
last_failure_retryable INTEGER,
|
|
36392
|
+
consecutive_failures INTEGER NOT NULL DEFAULT 0,
|
|
36393
|
+
vault_name TEXT,
|
|
36394
|
+
table_name TEXT,
|
|
36395
|
+
legacy_owner_identity TEXT,
|
|
36396
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
36397
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
36398
|
+
UNIQUE(user_id, provider_config_key, upstream_connection_id)
|
|
36399
|
+
)
|
|
36400
|
+
`);
|
|
36401
|
+
try {
|
|
36402
|
+
await db.execute(`ALTER TABLE service_connections ADD COLUMN user_label TEXT`);
|
|
36403
|
+
} catch {
|
|
36404
|
+
}
|
|
36405
|
+
try {
|
|
36406
|
+
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_id TEXT`);
|
|
36407
|
+
} catch {
|
|
36408
|
+
}
|
|
36409
|
+
try {
|
|
36410
|
+
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_email TEXT`);
|
|
36411
|
+
} catch {
|
|
36412
|
+
}
|
|
36413
|
+
try {
|
|
36414
|
+
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_name TEXT`);
|
|
36415
|
+
} catch {
|
|
36416
|
+
}
|
|
36417
|
+
try {
|
|
36418
|
+
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_identity_checked_at TEXT`);
|
|
36419
|
+
} catch {
|
|
36420
|
+
}
|
|
36421
|
+
try {
|
|
36422
|
+
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_identity_source_updated_at TEXT`);
|
|
36423
|
+
} catch {
|
|
36424
|
+
}
|
|
36425
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS service_connections_user_updated ON service_connections(user_id, updated_at DESC)`);
|
|
36426
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS service_connections_upstream ON service_connections(provider_config_key, upstream_connection_id)`);
|
|
36427
|
+
await db.execute(`
|
|
36428
|
+
CREATE TABLE IF NOT EXISTS service_connection_health_events (
|
|
36429
|
+
id TEXT PRIMARY KEY,
|
|
36430
|
+
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
36431
|
+
operational_status TEXT NOT NULL,
|
|
36432
|
+
failure_code TEXT,
|
|
36433
|
+
retryable INTEGER,
|
|
36434
|
+
evidence_source TEXT NOT NULL,
|
|
36435
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
36436
|
+
)
|
|
36437
|
+
`);
|
|
36438
|
+
await db.execute(`CREATE INDEX IF NOT EXISTS service_connection_health_events_connection ON service_connection_health_events(connection_id, created_at DESC)`);
|
|
36439
|
+
await db.execute(`
|
|
36440
|
+
CREATE TABLE IF NOT EXISTS service_connection_action_audit (
|
|
36441
|
+
id TEXT PRIMARY KEY,
|
|
36442
|
+
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
36443
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
36444
|
+
tool TEXT NOT NULL,
|
|
36445
|
+
request_id TEXT NOT NULL,
|
|
36446
|
+
status TEXT NOT NULL,
|
|
36447
|
+
error_code TEXT,
|
|
36448
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
36449
|
+
UNIQUE(user_id, request_id)
|
|
36450
|
+
)
|
|
36451
|
+
`);
|
|
36452
|
+
try {
|
|
36453
|
+
await db.execute(`ALTER TABLE service_connection_action_audit ADD COLUMN request_digest TEXT`);
|
|
36454
|
+
} catch {
|
|
36455
|
+
}
|
|
36456
|
+
try {
|
|
36457
|
+
await db.execute(`ALTER TABLE service_connection_action_audit ADD COLUMN result_json TEXT`);
|
|
36458
|
+
} catch {
|
|
36459
|
+
}
|
|
36460
|
+
})().catch((error) => {
|
|
36461
|
+
schemaReady = null;
|
|
36462
|
+
schemaDb5 = null;
|
|
36463
|
+
throw error;
|
|
36464
|
+
});
|
|
36465
|
+
return schemaReady;
|
|
36466
|
+
}
|
|
36467
|
+
function parseTools(value) {
|
|
36468
|
+
if (typeof value !== "string") return [];
|
|
36469
|
+
try {
|
|
36470
|
+
const parsed = JSON.parse(value);
|
|
36471
|
+
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
36472
|
+
} catch {
|
|
36473
|
+
return [];
|
|
36474
|
+
}
|
|
36475
|
+
}
|
|
36476
|
+
function rowToRecord(row) {
|
|
36477
|
+
return {
|
|
36478
|
+
id: String(row.id),
|
|
36479
|
+
userId: Number(row.user_id),
|
|
36480
|
+
providerConfigKey: String(row.provider_config_key),
|
|
36481
|
+
provider: typeof row.provider === "string" ? row.provider : null,
|
|
36482
|
+
transport: row.transport === "remote_mcp" ? "remote_mcp" : "nango",
|
|
36483
|
+
upstreamConnectionId: typeof row.upstream_connection_id === "string" ? row.upstream_connection_id : null,
|
|
36484
|
+
label: typeof row.label === "string" ? row.label : null,
|
|
36485
|
+
userLabel: typeof row.user_label === "string" ? row.user_label : null,
|
|
36486
|
+
providerAccountId: typeof row.provider_account_id === "string" ? row.provider_account_id : null,
|
|
36487
|
+
providerAccountEmail: typeof row.provider_account_email === "string" ? row.provider_account_email : null,
|
|
36488
|
+
providerAccountName: typeof row.provider_account_name === "string" ? row.provider_account_name : null,
|
|
36489
|
+
providerIdentityCheckedAt: typeof row.provider_identity_checked_at === "string" ? row.provider_identity_checked_at : null,
|
|
36490
|
+
providerIdentitySourceUpdatedAt: typeof row.provider_identity_source_updated_at === "string" ? row.provider_identity_source_updated_at : null,
|
|
36491
|
+
lifecycleStatus: String(row.lifecycle_status),
|
|
36492
|
+
operationalStatus: String(row.operational_status),
|
|
36493
|
+
reconnectRequired: Number(row.reconnect_required) === 1,
|
|
36494
|
+
actionsEnabled: Number(row.actions_enabled) === 1,
|
|
36495
|
+
readTools: parseTools(row.read_tools_json),
|
|
36496
|
+
actionTools: parseTools(row.action_tools_json),
|
|
36497
|
+
toolRevision: typeof row.tool_revision === "string" ? row.tool_revision : null,
|
|
36498
|
+
lastCheckedAt: typeof row.last_checked_at === "string" ? row.last_checked_at : null,
|
|
36499
|
+
lastSuccessfulCallAt: typeof row.last_successful_call_at === "string" ? row.last_successful_call_at : null,
|
|
36500
|
+
lastFailureAt: typeof row.last_failure_at === "string" ? row.last_failure_at : null,
|
|
36501
|
+
lastFailureCode: typeof row.last_failure_code === "string" ? row.last_failure_code : null,
|
|
36502
|
+
lastFailureRetryable: row.last_failure_retryable === null || row.last_failure_retryable === void 0 ? null : Number(row.last_failure_retryable) === 1,
|
|
36503
|
+
consecutiveFailures: Number(row.consecutive_failures ?? 0),
|
|
36504
|
+
vaultName: typeof row.vault_name === "string" ? row.vault_name : null,
|
|
36505
|
+
tableName: typeof row.table_name === "string" ? row.table_name : null,
|
|
36506
|
+
createdAt: String(row.created_at),
|
|
36507
|
+
updatedAt: String(row.updated_at)
|
|
36508
|
+
};
|
|
36509
|
+
}
|
|
36510
|
+
async function userIdForIdentity(identity) {
|
|
36511
|
+
const user = await getUserByEmail(identity.normalize("NFKC").trim().toLowerCase());
|
|
36512
|
+
if (!user) throw new Error("service_connection_user_not_found");
|
|
36513
|
+
return Number(user.id);
|
|
36514
|
+
}
|
|
36515
|
+
async function reconcileDiscoveredNangoConnections(identity, discovered) {
|
|
36516
|
+
await ensureServiceConnectionsSchema();
|
|
36517
|
+
const db = getDb();
|
|
36518
|
+
const userId = await userIdForIdentity(identity);
|
|
36519
|
+
for (const connection of discovered) {
|
|
36520
|
+
await db.execute({
|
|
36521
|
+
sql: `
|
|
36522
|
+
INSERT INTO service_connections (
|
|
36523
|
+
id, user_id, provider_config_key, provider, transport, upstream_connection_id,
|
|
36524
|
+
label, lifecycle_status, reconnect_required, actions_enabled, legacy_owner_identity, created_at, updated_at
|
|
36525
|
+
) VALUES (?, ?, ?, ?, 'nango', ?, ?, ?, ?, 1, ?, COALESCE(?, datetime('now')), COALESCE(?, datetime('now')))
|
|
36526
|
+
ON CONFLICT(user_id, provider_config_key, upstream_connection_id) DO UPDATE SET
|
|
36527
|
+
provider = excluded.provider,
|
|
36528
|
+
label = COALESCE(excluded.label, service_connections.label),
|
|
36529
|
+
lifecycle_status = excluded.lifecycle_status,
|
|
36530
|
+
reconnect_required = excluded.reconnect_required,
|
|
36531
|
+
updated_at = excluded.updated_at
|
|
36532
|
+
`,
|
|
36533
|
+
args: [
|
|
36534
|
+
(0, import_node_crypto21.randomUUID)(),
|
|
36535
|
+
userId,
|
|
36536
|
+
connection.providerConfigKey,
|
|
36537
|
+
connection.provider,
|
|
36538
|
+
connection.upstreamConnectionId,
|
|
36539
|
+
connection.label,
|
|
36540
|
+
connection.lifecycleStatus,
|
|
36541
|
+
connection.reconnectRequired ? 1 : 0,
|
|
36542
|
+
identity,
|
|
36543
|
+
connection.createdAt,
|
|
36544
|
+
connection.updatedAt
|
|
36545
|
+
]
|
|
36546
|
+
});
|
|
36547
|
+
}
|
|
36548
|
+
return listServiceConnections(identity, "nango");
|
|
36549
|
+
}
|
|
36550
|
+
async function listServiceConnections(identity, transport) {
|
|
36551
|
+
await ensureServiceConnectionsSchema();
|
|
36552
|
+
const userId = await userIdForIdentity(identity);
|
|
36553
|
+
const result = await getDb().execute({
|
|
36554
|
+
sql: `SELECT * FROM service_connections WHERE user_id = ?${transport ? " AND transport = ?" : ""} AND lifecycle_status <> 'disconnected' ORDER BY updated_at DESC`,
|
|
36555
|
+
args: transport ? [userId, transport] : [userId]
|
|
36556
|
+
});
|
|
36557
|
+
return result.rows.map((row) => rowToRecord(row));
|
|
36558
|
+
}
|
|
36559
|
+
async function getOwnedServiceConnection(identity, connectionId) {
|
|
36560
|
+
await ensureServiceConnectionsSchema();
|
|
36561
|
+
const userId = await userIdForIdentity(identity);
|
|
36562
|
+
const result = await getDb().execute({
|
|
36563
|
+
sql: "SELECT * FROM service_connections WHERE id = ? AND user_id = ? LIMIT 1",
|
|
36564
|
+
args: [connectionId, userId]
|
|
36565
|
+
});
|
|
36566
|
+
const row = result.rows[0];
|
|
36567
|
+
return row ? rowToRecord(row) : null;
|
|
36568
|
+
}
|
|
36569
|
+
async function updateServiceConnectionTools(connectionId, readTools, actionTools, toolRevision) {
|
|
36570
|
+
await ensureServiceConnectionsSchema();
|
|
36571
|
+
await getDb().execute({
|
|
36572
|
+
sql: `UPDATE service_connections SET read_tools_json = ?, action_tools_json = ?, tool_revision = ?, updated_at = datetime('now') WHERE id = ?`,
|
|
36573
|
+
args: [JSON.stringify(readTools), JSON.stringify(actionTools), toolRevision, connectionId]
|
|
36574
|
+
});
|
|
36575
|
+
}
|
|
36576
|
+
async function setServiceConnectionProviderIdentity(args) {
|
|
36577
|
+
await ensureServiceConnectionsSchema();
|
|
36578
|
+
await getDb().execute({
|
|
36579
|
+
sql: `
|
|
36580
|
+
UPDATE service_connections SET
|
|
36581
|
+
provider_account_id = ?, provider_account_email = ?, provider_account_name = ?,
|
|
36582
|
+
provider_identity_checked_at = datetime('now'), provider_identity_source_updated_at = ?,
|
|
36583
|
+
updated_at = datetime('now')
|
|
36584
|
+
WHERE id = ?
|
|
36585
|
+
`,
|
|
36586
|
+
args: [
|
|
36587
|
+
args.providerAccountId ?? null,
|
|
36588
|
+
args.providerAccountEmail?.toLowerCase() ?? null,
|
|
36589
|
+
args.providerAccountName ?? null,
|
|
36590
|
+
args.sourceUpdatedAt,
|
|
36591
|
+
args.connectionId
|
|
36592
|
+
]
|
|
36593
|
+
});
|
|
36594
|
+
}
|
|
36595
|
+
async function setServiceConnectionUserLabel(identity, connectionId, userLabel) {
|
|
36596
|
+
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
36597
|
+
if (!connection || connection.lifecycleStatus === "disconnected") throw new Error("service_connection_not_found");
|
|
36598
|
+
await getDb().execute({
|
|
36599
|
+
sql: `UPDATE service_connections SET user_label = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
36600
|
+
args: [userLabel, connectionId, connection.userId]
|
|
36601
|
+
});
|
|
36602
|
+
return userLabel;
|
|
36603
|
+
}
|
|
36604
|
+
async function recordServiceConnectionHealth(args) {
|
|
36605
|
+
await ensureServiceConnectionsSchema();
|
|
36606
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36607
|
+
await getDb().execute({
|
|
36608
|
+
sql: `
|
|
36609
|
+
UPDATE service_connections SET
|
|
36610
|
+
operational_status = ?, last_checked_at = ?,
|
|
36611
|
+
last_successful_call_at = CASE WHEN ? = 'available' THEN ? ELSE last_successful_call_at END,
|
|
36612
|
+
last_failure_at = CASE WHEN ? IN ('degraded', 'unavailable') THEN ? ELSE NULL END,
|
|
36613
|
+
last_failure_code = ?, last_failure_retryable = ?,
|
|
36614
|
+
consecutive_failures = CASE WHEN ? = 'available' THEN 0 ELSE consecutive_failures + 1 END,
|
|
36615
|
+
updated_at = datetime('now')
|
|
36616
|
+
WHERE id = ?
|
|
36617
|
+
`,
|
|
36618
|
+
args: [
|
|
36619
|
+
args.operationalStatus,
|
|
36620
|
+
now,
|
|
36621
|
+
args.operationalStatus,
|
|
36622
|
+
now,
|
|
36623
|
+
args.operationalStatus,
|
|
36624
|
+
now,
|
|
36625
|
+
args.failureCode ?? null,
|
|
36626
|
+
args.retryable == null ? null : args.retryable ? 1 : 0,
|
|
36627
|
+
args.operationalStatus,
|
|
36628
|
+
args.connectionId
|
|
36629
|
+
]
|
|
36630
|
+
});
|
|
36631
|
+
await getDb().execute({
|
|
36632
|
+
sql: `INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
36633
|
+
args: [(0, import_node_crypto21.randomUUID)(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
|
|
36634
|
+
});
|
|
36635
|
+
}
|
|
36636
|
+
async function setServiceConnectionActions(identity, connectionId, enabled) {
|
|
36637
|
+
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
36638
|
+
if (!connection || connection.lifecycleStatus === "disconnected") throw new Error("service_connection_not_found");
|
|
36639
|
+
await getDb().execute({
|
|
36640
|
+
sql: `UPDATE service_connections SET actions_enabled = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
36641
|
+
args: [enabled ? 1 : 0, connectionId, connection.userId]
|
|
36642
|
+
});
|
|
36643
|
+
return enabled;
|
|
36644
|
+
}
|
|
36645
|
+
async function markServiceConnectionDisconnected(identity, connectionId) {
|
|
36646
|
+
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
36647
|
+
if (!connection) throw new Error("service_connection_not_found");
|
|
36648
|
+
await getDb().execute({
|
|
36649
|
+
sql: `UPDATE service_connections SET lifecycle_status = 'disconnected', operational_status = 'unknown', reconnect_required = 0, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
36650
|
+
args: [connectionId, connection.userId]
|
|
36651
|
+
});
|
|
36652
|
+
const remaining = await getDb().execute({
|
|
36653
|
+
sql: `SELECT COUNT(*) AS count FROM service_connections WHERE user_id = ? AND transport = 'nango' AND lifecycle_status = 'connected'`,
|
|
36654
|
+
args: [connection.userId]
|
|
36655
|
+
});
|
|
36656
|
+
return Number(remaining.rows[0]?.count ?? 0);
|
|
36657
|
+
}
|
|
36658
|
+
async function recordServiceConnectionAction(args) {
|
|
36659
|
+
await ensureServiceConnectionsSchema();
|
|
36660
|
+
const connection = await getOwnedServiceConnection(args.identity, args.connectionId);
|
|
36661
|
+
if (!connection) throw new Error("service_connection_not_found");
|
|
36662
|
+
await getDb().execute({
|
|
36663
|
+
sql: `UPDATE service_connection_action_audit SET status = ?, error_code = ?, result_json = ? WHERE user_id = ? AND request_id = ? AND connection_id = ?`,
|
|
36664
|
+
args: [args.status, args.errorCode ?? null, args.result === void 0 ? null : JSON.stringify(args.result), connection.userId, args.requestId, connection.id]
|
|
36665
|
+
});
|
|
36666
|
+
}
|
|
36667
|
+
async function claimServiceConnectionAction(args) {
|
|
36668
|
+
await ensureServiceConnectionsSchema();
|
|
36669
|
+
const connection = await getOwnedServiceConnection(args.identity, args.connectionId);
|
|
36670
|
+
if (!connection) throw new Error("service_connection_not_found");
|
|
36671
|
+
const inserted = await getDb().execute({
|
|
36672
|
+
sql: `INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)`,
|
|
36673
|
+
args: [(0, import_node_crypto21.randomUUID)(), connection.id, connection.userId, args.tool, args.requestId, args.requestDigest]
|
|
36674
|
+
});
|
|
36675
|
+
if (Number(inserted.rowsAffected ?? 0) === 1) return { claimed: true };
|
|
36676
|
+
const existing = await getDb().execute({
|
|
36677
|
+
sql: `SELECT connection_id, tool, status, error_code, request_digest, result_json FROM service_connection_action_audit WHERE user_id = ? AND request_id = ? LIMIT 1`,
|
|
36678
|
+
args: [connection.userId, args.requestId]
|
|
36679
|
+
});
|
|
36680
|
+
const row = existing.rows[0];
|
|
36681
|
+
const conflict = String(row?.connection_id ?? "") !== connection.id || String(row?.tool ?? "") !== args.tool || String(row?.request_digest ?? "") !== args.requestDigest;
|
|
36682
|
+
let result = void 0;
|
|
36683
|
+
if (!conflict && typeof row?.result_json === "string") {
|
|
36684
|
+
try {
|
|
36685
|
+
result = JSON.parse(row.result_json);
|
|
36686
|
+
} catch {
|
|
36687
|
+
result = void 0;
|
|
36688
|
+
}
|
|
36689
|
+
}
|
|
36690
|
+
return {
|
|
36691
|
+
claimed: false,
|
|
36692
|
+
status: String(row?.status ?? "unknown"),
|
|
36693
|
+
errorCode: typeof row?.error_code === "string" ? row.error_code : null,
|
|
36694
|
+
conflict,
|
|
36695
|
+
...result !== void 0 ? { result } : {}
|
|
36696
|
+
};
|
|
36697
|
+
}
|
|
36698
|
+
var import_node_crypto21, schemaReady, schemaDb5;
|
|
36699
|
+
var init_service_connections = __esm({
|
|
36700
|
+
"src/api/service-connections.ts"() {
|
|
36701
|
+
"use strict";
|
|
36702
|
+
import_node_crypto21 = require("crypto");
|
|
36703
|
+
init_db();
|
|
36704
|
+
schemaReady = null;
|
|
36705
|
+
schemaDb5 = null;
|
|
36706
|
+
}
|
|
36707
|
+
});
|
|
36708
|
+
|
|
36291
36709
|
// src/api/connected-account-billing.ts
|
|
36292
36710
|
function connectedBillingPeriodStart(now = /* @__PURE__ */ new Date()) {
|
|
36293
36711
|
return `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, "0")}`;
|
|
@@ -36302,6 +36720,87 @@ async function chargedConnectionIds(userId, periodStart) {
|
|
|
36302
36720
|
});
|
|
36303
36721
|
return new Set(result.rows.map((row) => String(row.connection_id)));
|
|
36304
36722
|
}
|
|
36723
|
+
async function inheritDisconnectedConnectionCharge(userId, connectionId, periodStart) {
|
|
36724
|
+
await ensureServiceConnectionsSchema();
|
|
36725
|
+
const normalizedUserId = Number(userId);
|
|
36726
|
+
const db = getDb();
|
|
36727
|
+
await db.batch([
|
|
36728
|
+
{
|
|
36729
|
+
sql: `
|
|
36730
|
+
INSERT OR IGNORE INTO connected_account_charge_transfers (
|
|
36731
|
+
user_id, period_start, from_connection_id, to_connection_id, provider_config_key
|
|
36732
|
+
)
|
|
36733
|
+
SELECT ?, ?, previous.id, replacement.id, replacement.provider_config_key
|
|
36734
|
+
FROM service_connections AS replacement
|
|
36735
|
+
JOIN service_connections AS previous
|
|
36736
|
+
ON previous.user_id = replacement.user_id
|
|
36737
|
+
AND previous.transport = 'nango'
|
|
36738
|
+
AND previous.provider_config_key = replacement.provider_config_key
|
|
36739
|
+
AND previous.lifecycle_status = 'disconnected'
|
|
36740
|
+
JOIN connected_account_charges AS charge
|
|
36741
|
+
ON charge.user_id = previous.user_id
|
|
36742
|
+
AND charge.connection_id = previous.id
|
|
36743
|
+
AND charge.period_start = ?
|
|
36744
|
+
WHERE replacement.id = ?
|
|
36745
|
+
AND replacement.user_id = ?
|
|
36746
|
+
AND replacement.transport = 'nango'
|
|
36747
|
+
AND replacement.lifecycle_status IN ('connected', 'needs_reauth')
|
|
36748
|
+
AND NOT EXISTS (
|
|
36749
|
+
SELECT 1 FROM connected_account_charges AS existing
|
|
36750
|
+
WHERE existing.user_id = replacement.user_id
|
|
36751
|
+
AND existing.connection_id = replacement.id
|
|
36752
|
+
AND existing.period_start = ?
|
|
36753
|
+
)
|
|
36754
|
+
ORDER BY previous.updated_at DESC, previous.id ASC
|
|
36755
|
+
LIMIT 1
|
|
36756
|
+
`,
|
|
36757
|
+
args: [normalizedUserId, periodStart, periodStart, connectionId, normalizedUserId, periodStart]
|
|
36758
|
+
},
|
|
36759
|
+
{
|
|
36760
|
+
sql: `
|
|
36761
|
+
UPDATE connected_account_charges
|
|
36762
|
+
SET connection_id = ?
|
|
36763
|
+
WHERE user_id = ?
|
|
36764
|
+
AND period_start = ?
|
|
36765
|
+
AND connection_id = (
|
|
36766
|
+
SELECT transfer.from_connection_id
|
|
36767
|
+
FROM connected_account_charge_transfers AS transfer
|
|
36768
|
+
JOIN connected_account_charges AS current_charge
|
|
36769
|
+
ON current_charge.user_id = transfer.user_id
|
|
36770
|
+
AND current_charge.period_start = transfer.period_start
|
|
36771
|
+
AND current_charge.connection_id = transfer.from_connection_id
|
|
36772
|
+
WHERE transfer.user_id = ?
|
|
36773
|
+
AND transfer.period_start = ?
|
|
36774
|
+
AND transfer.to_connection_id = ?
|
|
36775
|
+
ORDER BY transfer.transferred_at DESC, transfer.id DESC
|
|
36776
|
+
LIMIT 1
|
|
36777
|
+
)
|
|
36778
|
+
AND NOT EXISTS (
|
|
36779
|
+
SELECT 1 FROM connected_account_charges AS existing
|
|
36780
|
+
WHERE existing.user_id = ?
|
|
36781
|
+
AND existing.connection_id = ?
|
|
36782
|
+
AND existing.period_start = ?
|
|
36783
|
+
)
|
|
36784
|
+
`,
|
|
36785
|
+
args: [
|
|
36786
|
+
connectionId,
|
|
36787
|
+
normalizedUserId,
|
|
36788
|
+
periodStart,
|
|
36789
|
+
normalizedUserId,
|
|
36790
|
+
periodStart,
|
|
36791
|
+
connectionId,
|
|
36792
|
+
normalizedUserId,
|
|
36793
|
+
connectionId,
|
|
36794
|
+
periodStart
|
|
36795
|
+
]
|
|
36796
|
+
}
|
|
36797
|
+
], "write");
|
|
36798
|
+
const inherited = await db.execute({
|
|
36799
|
+
sql: "SELECT 1 FROM connected_account_charges WHERE user_id = ? AND connection_id = ? AND period_start = ? LIMIT 1",
|
|
36800
|
+
args: [normalizedUserId, connectionId, periodStart]
|
|
36801
|
+
});
|
|
36802
|
+
return inherited.rows.length > 0;
|
|
36803
|
+
}
|
|
36305
36804
|
async function getConnectedAccountBillingState2(userId) {
|
|
36306
36805
|
const result = await getDb().execute({
|
|
36307
36806
|
sql: "SELECT * FROM connected_account_billing WHERE user_id = ? LIMIT 1",
|
|
@@ -36430,6 +36929,7 @@ async function reconcileConnectedAccountBilling(user, connections) {
|
|
|
36430
36929
|
const alreadyCharged = await chargedConnectionIds(user.id, periodStart);
|
|
36431
36930
|
const unpaid = billableConnectionIds.filter((id) => !alreadyCharged.has(id));
|
|
36432
36931
|
for (const connectionId of unpaid) {
|
|
36932
|
+
if (await inheritDisconnectedConnectionCharge(user.id, connectionId, periodStart)) continue;
|
|
36433
36933
|
const feeMc = CONNECTED_ACTIVE_CONNECTION_MONTHLY_MC;
|
|
36434
36934
|
const debit = await debitMcIdempotent(
|
|
36435
36935
|
user.id,
|
|
@@ -36491,6 +36991,7 @@ var init_connected_account_billing = __esm({
|
|
|
36491
36991
|
init_db();
|
|
36492
36992
|
init_rates();
|
|
36493
36993
|
init_connected_cost_telemetry();
|
|
36994
|
+
init_service_connections();
|
|
36494
36995
|
DEFAULT_CONNECTED_ACCOUNT_PRICE_ID = "price_1TtYPAS8aAcsk3TGHOgrDZiQ";
|
|
36495
36996
|
BILLABLE_LIFECYCLE = /* @__PURE__ */ new Set(["connected", "needs_reauth"]);
|
|
36496
36997
|
ConnectedAccountBillingError = class extends Error {
|
|
@@ -40059,7 +40560,7 @@ async function applyAdjustment(input) {
|
|
|
40059
40560
|
const credits = validateCredits(input.credits, input.confirmLarge === true);
|
|
40060
40561
|
const reason = validateReason(input.reason);
|
|
40061
40562
|
const actor = validateActor(input.actor);
|
|
40062
|
-
const reference = input.reference?.trim() || `adj_${(0,
|
|
40563
|
+
const reference = input.reference?.trim() || `adj_${(0, import_node_crypto22.randomUUID)()}`;
|
|
40063
40564
|
if (reference.length > 120) throw new AdminCreditError(400, "reference must be at most 120 characters");
|
|
40064
40565
|
const db = getDb();
|
|
40065
40566
|
const existing = await db.execute({
|
|
@@ -40204,11 +40705,11 @@ async function lookupAccount(target, limit = 20) {
|
|
|
40204
40705
|
}))
|
|
40205
40706
|
};
|
|
40206
40707
|
}
|
|
40207
|
-
var
|
|
40708
|
+
var import_node_crypto22, MIN_ADJUSTMENT_CREDITS, LARGE_ADJUSTMENT_CREDITS, MAX_ADJUSTMENT_CREDITS, MIN_REASON_LENGTH, MAX_REASON_LENGTH, MAX_ACTOR_LENGTH, AdminCreditError;
|
|
40208
40709
|
var init_admin_credits = __esm({
|
|
40209
40710
|
"src/api/admin-credits.ts"() {
|
|
40210
40711
|
"use strict";
|
|
40211
|
-
|
|
40712
|
+
import_node_crypto22 = require("crypto");
|
|
40212
40713
|
init_db();
|
|
40213
40714
|
init_rates();
|
|
40214
40715
|
MIN_ADJUSTMENT_CREDITS = 1;
|
|
@@ -42173,7 +42674,7 @@ async function packageMapsMedia(args) {
|
|
|
42173
42674
|
files.push({ path: "summary.json", content: Buffer.from(JSON.stringify(summary, null, 2)) });
|
|
42174
42675
|
files.push({ path: "images.jsonl", content: Buffer.from(cleanImages.map((image) => JSON.stringify(image)).join("\n") + "\n") });
|
|
42175
42676
|
const archive = await zipBuffer(files);
|
|
42176
|
-
const id = (0,
|
|
42677
|
+
const id = (0, import_node_crypto23.randomBytes)(6).toString("hex");
|
|
42177
42678
|
const pointer = await createPrivateArtifact({
|
|
42178
42679
|
policy: policy3(),
|
|
42179
42680
|
ownerId: args.ownerId,
|
|
@@ -42186,13 +42687,13 @@ async function packageMapsMedia(args) {
|
|
|
42186
42687
|
const localPath = token() ? null : (0, import_node_path13.join)(process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || (0, import_node_path13.join)((0, import_node_os9.homedir)(), "Downloads", "mcp-scraper"), "blobs", pointer.artifactId);
|
|
42187
42688
|
return { media: args.media, artifact: { ...pointer, localPath } };
|
|
42188
42689
|
}
|
|
42189
|
-
var import_node_os9, import_node_path13,
|
|
42690
|
+
var import_node_os9, import_node_path13, import_node_crypto23, import_yazl2, import_p_limit5, MAPS_MEDIA_ARTIFACT_PREFIX, MAPS_MEDIA_ARTIFACT_TTL_MS, MAPS_MEDIA_DOWNLOAD_TTL_MS, MAX_IMAGE_BYTES2, MAX_ARCHIVE_IMAGE_BYTES, MAX_INLINE_IMAGE_BYTES, MAX_INLINE_TOTAL_BYTES, DOWNLOAD_CONCURRENCY, MAX_REDIRECTS;
|
|
42190
42691
|
var init_maps_media_artifacts = __esm({
|
|
42191
42692
|
"src/api/maps-media-artifacts.ts"() {
|
|
42192
42693
|
"use strict";
|
|
42193
42694
|
import_node_os9 = require("os");
|
|
42194
42695
|
import_node_path13 = require("path");
|
|
42195
|
-
|
|
42696
|
+
import_node_crypto23 = require("crypto");
|
|
42196
42697
|
import_yazl2 = require("yazl");
|
|
42197
42698
|
import_p_limit5 = __toESM(require("p-limit"), 1);
|
|
42198
42699
|
init_private_artifacts();
|
|
@@ -42816,7 +43317,7 @@ function retryDelaySeconds(attempts) {
|
|
|
42816
43317
|
}
|
|
42817
43318
|
async function dispatchPendingDirectoryWorkflows(limit = 25) {
|
|
42818
43319
|
const rows = await claimDirectoryWorkflowOutbox({
|
|
42819
|
-
workerId: `directory-dispatch-${process.pid}-${(0,
|
|
43320
|
+
workerId: `directory-dispatch-${process.pid}-${(0, import_node_crypto24.randomUUID)().slice(0, 8)}`,
|
|
42820
43321
|
limit
|
|
42821
43322
|
});
|
|
42822
43323
|
const result = { claimed: rows.length, dispatched: 0, failed: 0 };
|
|
@@ -42838,11 +43339,11 @@ async function dispatchPendingDirectoryWorkflows(limit = 25) {
|
|
|
42838
43339
|
}
|
|
42839
43340
|
return result;
|
|
42840
43341
|
}
|
|
42841
|
-
var
|
|
43342
|
+
var import_node_crypto24;
|
|
42842
43343
|
var init_directory_workflow_dispatch = __esm({
|
|
42843
43344
|
"src/api/directory-workflow-dispatch.ts"() {
|
|
42844
43345
|
"use strict";
|
|
42845
|
-
|
|
43346
|
+
import_node_crypto24 = require("crypto");
|
|
42846
43347
|
init_client();
|
|
42847
43348
|
init_directory_workflow_repository();
|
|
42848
43349
|
}
|
|
@@ -42854,7 +43355,7 @@ function safeOptions(options) {
|
|
|
42854
43355
|
return safe2;
|
|
42855
43356
|
}
|
|
42856
43357
|
function requestFingerprint(options) {
|
|
42857
|
-
return (0,
|
|
43358
|
+
return (0, import_node_crypto25.createHash)("sha256").update(JSON.stringify(safeOptions(options))).digest("hex");
|
|
42858
43359
|
}
|
|
42859
43360
|
function idempotencyKey(raw) {
|
|
42860
43361
|
if (raw !== void 0) {
|
|
@@ -42863,14 +43364,14 @@ function idempotencyKey(raw) {
|
|
|
42863
43364
|
if (trimmed.length > 500) return { ok: false, message: "Idempotency-Key must be 500 characters or fewer." };
|
|
42864
43365
|
return { ok: true, key: trimmed };
|
|
42865
43366
|
}
|
|
42866
|
-
return { ok: true, key: `directory-${(0,
|
|
43367
|
+
return { ok: true, key: `directory-${(0, import_node_crypto25.randomUUID)()}` };
|
|
42867
43368
|
}
|
|
42868
43369
|
function debitKeyFor(userId, responseKey) {
|
|
42869
|
-
const digest2 = (0,
|
|
43370
|
+
const digest2 = (0, import_node_crypto25.createHash)("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
|
|
42870
43371
|
return `directory-workflow:${userId}:${digest2}`;
|
|
42871
43372
|
}
|
|
42872
43373
|
function jobId() {
|
|
42873
|
-
return `dir_${(0,
|
|
43374
|
+
return `dir_${(0, import_node_crypto25.randomUUID)().replace(/-/g, "")}`;
|
|
42874
43375
|
}
|
|
42875
43376
|
function publicStatus(job, result) {
|
|
42876
43377
|
if (job.status === "failed") return "failed";
|
|
@@ -42979,7 +43480,7 @@ async function runSynchronously(c, user, options, plan, responseKey) {
|
|
|
42979
43480
|
const csv = renderDirectoryWorkflowCsv(result);
|
|
42980
43481
|
const artifact = await createDirectoryCsvArtifact({
|
|
42981
43482
|
ownerId: String(user.id),
|
|
42982
|
-
jobId: (0,
|
|
43483
|
+
jobId: (0, import_node_crypto25.createHash)("sha256").update(debitKey2).digest("hex").slice(0, 32),
|
|
42983
43484
|
createdAt: result.extractedAt,
|
|
42984
43485
|
filename: `${options.state}-${options.query}-directory.csv`,
|
|
42985
43486
|
csv,
|
|
@@ -43035,11 +43536,11 @@ async function runSynchronously(c, user, options, plan, responseKey) {
|
|
|
43035
43536
|
await releaseConcurrencyGate(gate.lockId);
|
|
43036
43537
|
}
|
|
43037
43538
|
}
|
|
43038
|
-
var
|
|
43539
|
+
var import_node_crypto25, import_hono16, directoryApp;
|
|
43039
43540
|
var init_directory_routes = __esm({
|
|
43040
43541
|
"src/api/directory-routes.ts"() {
|
|
43041
43542
|
"use strict";
|
|
43042
|
-
|
|
43543
|
+
import_node_crypto25 = require("crypto");
|
|
43043
43544
|
import_hono16 = require("hono");
|
|
43044
43545
|
init_api_auth();
|
|
43045
43546
|
init_db();
|
|
@@ -43257,15 +43758,15 @@ function bounded(value, field, min, max) {
|
|
|
43257
43758
|
return normalized;
|
|
43258
43759
|
}
|
|
43259
43760
|
function newLeadListUploadId() {
|
|
43260
|
-
return `upl_${(0,
|
|
43761
|
+
return `upl_${(0, import_node_crypto26.randomUUID)().replace(/-/g, "")}`;
|
|
43261
43762
|
}
|
|
43262
43763
|
function newImportedLeadListId() {
|
|
43263
|
-
return `lst_${(0,
|
|
43764
|
+
return `lst_${(0, import_node_crypto26.randomUUID)().replace(/-/g, "")}`;
|
|
43264
43765
|
}
|
|
43265
43766
|
async function ensureLeadListImportRepositorySchema() {
|
|
43266
43767
|
const db = getDb();
|
|
43267
|
-
if (
|
|
43268
|
-
|
|
43768
|
+
if (schemaDb6 !== db) {
|
|
43769
|
+
schemaDb6 = db;
|
|
43269
43770
|
schemaPromise5 = null;
|
|
43270
43771
|
}
|
|
43271
43772
|
if (!schemaPromise5) {
|
|
@@ -43460,13 +43961,13 @@ async function deleteExpiredLeadListInputRecords(now = /* @__PURE__ */ new Date(
|
|
|
43460
43961
|
], "write");
|
|
43461
43962
|
return { uploads: Number(uploads.rowsAffected ?? 0), lists: Number(lists.rowsAffected ?? 0) };
|
|
43462
43963
|
}
|
|
43463
|
-
var
|
|
43964
|
+
var import_node_crypto26, schemaDb6, schemaPromise5;
|
|
43464
43965
|
var init_lead_list_import_repository = __esm({
|
|
43465
43966
|
"src/api/lead-list-import-repository.ts"() {
|
|
43466
43967
|
"use strict";
|
|
43467
|
-
|
|
43968
|
+
import_node_crypto26 = require("crypto");
|
|
43468
43969
|
init_db();
|
|
43469
|
-
|
|
43970
|
+
schemaDb6 = null;
|
|
43470
43971
|
schemaPromise5 = null;
|
|
43471
43972
|
}
|
|
43472
43973
|
});
|
|
@@ -43506,7 +44007,7 @@ function safeFilenameHint(value) {
|
|
|
43506
44007
|
return cleaned || null;
|
|
43507
44008
|
}
|
|
43508
44009
|
function requestFingerprint2(filenameHint) {
|
|
43509
|
-
return (0,
|
|
44010
|
+
return (0, import_node_crypto27.createHash)("sha256").update(JSON.stringify({ filenameHint })).digest("hex");
|
|
43510
44011
|
}
|
|
43511
44012
|
function publicBaseUrl() {
|
|
43512
44013
|
const configured = process.env.MCP_SCRAPER_PUBLIC_BASE_URL?.trim() || process.env.PUBLIC_BASE_URL?.trim() || (process.env.VERCEL_PROJECT_PRODUCTION_URL ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` : "") || "https://mcpscraper.dev";
|
|
@@ -43662,7 +44163,7 @@ async function inspectLeadListUpload(uploadId, ownerId2) {
|
|
|
43662
44163
|
maxBytes: LEAD_LIST_UPLOAD_MAX_BYTES
|
|
43663
44164
|
});
|
|
43664
44165
|
if (!buffer) return null;
|
|
43665
|
-
const sha2565 = (0,
|
|
44166
|
+
const sha2565 = (0, import_node_crypto27.createHash)("sha256").update(buffer).digest("hex");
|
|
43666
44167
|
const completed = await completeLeadListUpload({
|
|
43667
44168
|
id: record.id,
|
|
43668
44169
|
ownerId: record.ownerId,
|
|
@@ -43786,11 +44287,11 @@ async function cleanupExpiredLeadListInputs(args = {}) {
|
|
|
43786
44287
|
const records = await deleteExpiredLeadListInputRecords(now);
|
|
43787
44288
|
return { deletedBlobs, deletedUploadRecords: records.uploads, deletedListRecords: records.lists };
|
|
43788
44289
|
}
|
|
43789
|
-
var
|
|
44290
|
+
var import_node_crypto27, import_promises11, import_node_os10, import_node_path14, LEAD_LIST_UPLOAD_PREFIX, LEAD_LIST_NORMALIZED_PREFIX, LEAD_LIST_UPLOAD_MAX_BYTES, LEAD_LIST_UPLOAD_URL_TTL_MS, LEAD_LIST_UPLOAD_SOURCE_TTL_MS, LEAD_LIST_NORMALIZED_TTL_MS, LEAD_LIST_DOWNLOAD_TTL_MS, LEAD_LIST_UPLOAD_MIME_TYPES;
|
|
43790
44291
|
var init_lead_list_input_artifacts = __esm({
|
|
43791
44292
|
"src/api/lead-list-input-artifacts.ts"() {
|
|
43792
44293
|
"use strict";
|
|
43793
|
-
|
|
44294
|
+
import_node_crypto27 = require("crypto");
|
|
43794
44295
|
import_promises11 = require("fs/promises");
|
|
43795
44296
|
import_node_os10 = require("os");
|
|
43796
44297
|
import_node_path14 = require("path");
|
|
@@ -44173,7 +44674,7 @@ function canonicalize(value) {
|
|
|
44173
44674
|
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalize(object[key])}`).join(",")}}`;
|
|
44174
44675
|
}
|
|
44175
44676
|
function fingerprint(value) {
|
|
44176
|
-
return (0,
|
|
44677
|
+
return (0, import_node_crypto28.createHash)("sha256").update(canonicalize(value)).digest("hex");
|
|
44177
44678
|
}
|
|
44178
44679
|
async function safeJson(c) {
|
|
44179
44680
|
try {
|
|
@@ -44250,11 +44751,11 @@ function textDelimiter(raw, text2, observedMime) {
|
|
|
44250
44751
|
if (observedMime === "text/tab-separated-values") return " ";
|
|
44251
44752
|
return detectLeadListTextDelimiter(text2);
|
|
44252
44753
|
}
|
|
44253
|
-
var
|
|
44754
|
+
var import_node_crypto28, import_hono17, leadListInputApp;
|
|
44254
44755
|
var init_lead_list_input_routes = __esm({
|
|
44255
44756
|
"src/api/lead-list-input-routes.ts"() {
|
|
44256
44757
|
"use strict";
|
|
44257
|
-
|
|
44758
|
+
import_node_crypto28 = require("crypto");
|
|
44258
44759
|
import_hono17 = require("hono");
|
|
44259
44760
|
init_api_auth();
|
|
44260
44761
|
init_lead_list_input_artifacts();
|
|
@@ -44446,7 +44947,7 @@ function retryDelaySeconds2(attempts) {
|
|
|
44446
44947
|
return Math.min(3600, Math.max(15, 15 * 2 ** Math.min(8, Math.max(0, attempts - 1))));
|
|
44447
44948
|
}
|
|
44448
44949
|
async function dispatchPendingLeadListEnrichments(limit = 25) {
|
|
44449
|
-
const rows = await claimLeadListEnrichmentOutbox({ workerId: `lead-list-dispatch-${process.pid}-${(0,
|
|
44950
|
+
const rows = await claimLeadListEnrichmentOutbox({ workerId: `lead-list-dispatch-${process.pid}-${(0, import_node_crypto29.randomUUID)().slice(0, 8)}`, limit });
|
|
44450
44951
|
const result = { claimed: rows.length, dispatched: 0, failed: 0 };
|
|
44451
44952
|
for (const row of rows) {
|
|
44452
44953
|
if (!row.claimToken) continue;
|
|
@@ -44465,11 +44966,11 @@ async function dispatchPendingLeadListEnrichments(limit = 25) {
|
|
|
44465
44966
|
}
|
|
44466
44967
|
return result;
|
|
44467
44968
|
}
|
|
44468
|
-
var
|
|
44969
|
+
var import_node_crypto29;
|
|
44469
44970
|
var init_lead_list_enrichment_dispatch = __esm({
|
|
44470
44971
|
"src/api/lead-list-enrichment-dispatch.ts"() {
|
|
44471
44972
|
"use strict";
|
|
44472
|
-
|
|
44973
|
+
import_node_crypto29 = require("crypto");
|
|
44473
44974
|
init_client();
|
|
44474
44975
|
init_lead_list_enrichment_repository();
|
|
44475
44976
|
}
|
|
@@ -44485,15 +44986,15 @@ function idempotencyKey2(raw) {
|
|
|
44485
44986
|
return { ok: true, value };
|
|
44486
44987
|
}
|
|
44487
44988
|
function newJobId() {
|
|
44488
|
-
return `lle_${(0,
|
|
44989
|
+
return `lle_${(0, import_node_crypto30.randomUUID)().replace(/-/g, "")}`;
|
|
44489
44990
|
}
|
|
44490
44991
|
function debitKeyFor2(userId, key) {
|
|
44491
|
-
const digest2 = (0,
|
|
44992
|
+
const digest2 = (0, import_node_crypto30.createHash)("sha256").update(String(userId)).update("\0").update(key).digest("hex");
|
|
44492
44993
|
return `lead-list-enrichment:${userId}:${digest2}`;
|
|
44493
44994
|
}
|
|
44494
44995
|
function inlineSourceDigest(headers, rows) {
|
|
44495
44996
|
const values = rows.map((row) => headers.map((header) => row[header] ?? null));
|
|
44496
|
-
return (0,
|
|
44997
|
+
return (0, import_node_crypto30.createHash)("sha256").update(stableCanonicalJson({ headers, values })).digest("hex");
|
|
44497
44998
|
}
|
|
44498
44999
|
function issueMessage(error) {
|
|
44499
45000
|
const issue = error.issues[0];
|
|
@@ -44691,11 +45192,11 @@ async function resolveInput(ownerId2, parsed) {
|
|
|
44691
45192
|
sourceDigest: sourceDigest ?? inlineSourceDigest(normalized.headers, rows)
|
|
44692
45193
|
};
|
|
44693
45194
|
}
|
|
44694
|
-
var
|
|
45195
|
+
var import_node_crypto30, import_hono18, import_zod31, SourceSchema, StartSchema, TERMINAL, leadListEnrichmentApp;
|
|
44695
45196
|
var init_lead_list_enrichment_routes = __esm({
|
|
44696
45197
|
"src/api/lead-list-enrichment-routes.ts"() {
|
|
44697
45198
|
"use strict";
|
|
44698
|
-
|
|
45199
|
+
import_node_crypto30 = require("crypto");
|
|
44699
45200
|
import_hono18 = require("hono");
|
|
44700
45201
|
import_zod31 = require("zod");
|
|
44701
45202
|
init_api_auth();
|
|
@@ -48162,7 +48663,7 @@ async function readManifestFromSummary(summary) {
|
|
|
48162
48663
|
function webhookSignature(body, timestamp2) {
|
|
48163
48664
|
const secret2 = process.env.MCP_SCRAPER_WEBHOOK_SECRET?.trim();
|
|
48164
48665
|
if (!secret2) return null;
|
|
48165
|
-
return (0,
|
|
48666
|
+
return (0, import_node_crypto31.createHmac)("sha256", secret2).update(`${timestamp2}.${body}`).digest("hex");
|
|
48166
48667
|
}
|
|
48167
48668
|
async function deliverWorkflowWebhook(input) {
|
|
48168
48669
|
if (!input.webhookUrl) return;
|
|
@@ -48369,11 +48870,11 @@ async function dispatchDueWorkflowSchedules(apiUrl, limit = 3) {
|
|
|
48369
48870
|
}
|
|
48370
48871
|
return { dispatched: results.length, results };
|
|
48371
48872
|
}
|
|
48372
|
-
var
|
|
48873
|
+
var import_node_crypto31, import_promises14, import_hono21, import_zod41, workflowApp, WorkflowInputSchema, WorkflowIdSchema, CadenceSchema, ScheduleStatusSchema, RunBodySchema, ScheduleCreateSchema, SchedulePatchSchema, TERMINAL_RUN_STATUSES;
|
|
48373
48874
|
var init_workflow_routes = __esm({
|
|
48374
48875
|
"src/api/workflow-routes.ts"() {
|
|
48375
48876
|
"use strict";
|
|
48376
|
-
|
|
48877
|
+
import_node_crypto31 = require("crypto");
|
|
48377
48878
|
import_promises14 = require("fs/promises");
|
|
48378
48879
|
import_hono21 = require("hono");
|
|
48379
48880
|
import_zod41 = require("zod");
|
|
@@ -48654,7 +49155,7 @@ var init_workflow_routes = __esm({
|
|
|
48654
49155
|
// src/serp-intelligence/page-snapshot-extractor.ts
|
|
48655
49156
|
function sha2562(value) {
|
|
48656
49157
|
if (!value) return null;
|
|
48657
|
-
return (0,
|
|
49158
|
+
return (0, import_node_crypto32.createHash)("sha256").update(value).digest("hex");
|
|
48658
49159
|
}
|
|
48659
49160
|
function countWords(markdown) {
|
|
48660
49161
|
const matches = markdown.trim().match(/\b[\p{L}\p{N}][\p{L}\p{N}'-]*\b/gu);
|
|
@@ -48954,11 +49455,11 @@ async function capturePageSnapshots(targets, options = {}) {
|
|
|
48954
49455
|
}
|
|
48955
49456
|
};
|
|
48956
49457
|
}
|
|
48957
|
-
var
|
|
49458
|
+
var import_node_crypto32, import_p_limit6, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_CONTENT_CHARS;
|
|
48958
49459
|
var init_page_snapshot_extractor = __esm({
|
|
48959
49460
|
"src/serp-intelligence/page-snapshot-extractor.ts"() {
|
|
48960
49461
|
"use strict";
|
|
48961
|
-
|
|
49462
|
+
import_node_crypto32 = require("crypto");
|
|
48962
49463
|
import_p_limit6 = __toESM(require("p-limit"), 1);
|
|
48963
49464
|
init_kpo_extractor();
|
|
48964
49465
|
init_url_utils();
|
|
@@ -49455,21 +49956,21 @@ async function logRequestEventBestEffort(input) {
|
|
|
49455
49956
|
}
|
|
49456
49957
|
}
|
|
49457
49958
|
function captureBillingKeys(userId, suppliedKey, body) {
|
|
49458
|
-
const responseKey = suppliedKey?.trim() || (0,
|
|
49459
|
-
const requestFingerprint3 = (0,
|
|
49460
|
-
const keyDigest = (0,
|
|
49959
|
+
const responseKey = suppliedKey?.trim() || (0, import_node_crypto33.randomUUID)();
|
|
49960
|
+
const requestFingerprint3 = (0, import_node_crypto33.createHash)("sha256").update(JSON.stringify(body)).digest("hex");
|
|
49961
|
+
const keyDigest = (0, import_node_crypto33.createHash)("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
|
|
49461
49962
|
return {
|
|
49462
49963
|
responseKey,
|
|
49463
49964
|
debitKey: `serp-capture:${userId}:${keyDigest}`,
|
|
49464
49965
|
debitDescription: `${body.query} [request:${requestFingerprint3}]`
|
|
49465
49966
|
};
|
|
49466
49967
|
}
|
|
49467
|
-
var import_hono22,
|
|
49968
|
+
var import_hono22, import_node_crypto33, SERP_INTELLIGENCE_RATE_LIMIT, SERP_INTELLIGENCE_RATE_WINDOW_SECONDS, POST_CAPTURE_ROUTE_LABEL, POST_PAGE_SNAPSHOTS_ROUTE_LABEL, SERP_CAPTURE_BILLING_SOURCE, serpIntelligenceApp;
|
|
49468
49969
|
var init_serp_intelligence_routes = __esm({
|
|
49469
49970
|
"src/api/serp-intelligence-routes.ts"() {
|
|
49470
49971
|
"use strict";
|
|
49471
49972
|
import_hono22 = require("hono");
|
|
49472
|
-
|
|
49973
|
+
import_node_crypto33 = require("crypto");
|
|
49473
49974
|
init_browser_service_env();
|
|
49474
49975
|
init_page_snapshot_extractor();
|
|
49475
49976
|
init_serp_capture_service();
|
|
@@ -49706,7 +50207,7 @@ var PACKAGE_VERSION;
|
|
|
49706
50207
|
var init_version = __esm({
|
|
49707
50208
|
"src/version.ts"() {
|
|
49708
50209
|
"use strict";
|
|
49709
|
-
PACKAGE_VERSION = "0.66.
|
|
50210
|
+
PACKAGE_VERSION = "0.66.7";
|
|
49710
50211
|
}
|
|
49711
50212
|
});
|
|
49712
50213
|
|
|
@@ -49775,11 +50276,20 @@ seam is noted so you can chain them.
|
|
|
49775
50276
|
- Plan a new or edited entity -> **commons_prepare_entity**. This is the Commons equivalent of
|
|
49776
50277
|
prepare-memory-write: it returns the live entity profile contract, duplicate candidates, tag reuse/review/create
|
|
49777
50278
|
guidance, recommended sections, optional sections, and heading guidance before any write occurs.
|
|
49778
|
-
-
|
|
49779
|
-
|
|
49780
|
-
|
|
50279
|
+
- Host a featured image -> **commons_host_image**. The normal write sequence is **commons_prepare_entity ->
|
|
50280
|
+
compose the payload -> commons_host_image -> commons_validate_entity -> commons_submit_entity**. Put the
|
|
50281
|
+
permanent returned URL in featuredImage.url. Use imageBase64 for available attachment bytes within the request
|
|
50282
|
+
bound, or a stable direct public HTTPS image URL; never use a caller-local path, opaque chat attachment reference,
|
|
50283
|
+
HTML page, private URL, or temporary/signed URL.
|
|
50284
|
+
- Validate a composed entity without writing -> **commons_validate_entity**. Use it after image hosting and before
|
|
50285
|
+
submit. Validation does not fetch or store image bytes; an external/unregistered featured image is reported in
|
|
50286
|
+
imageDiagnostics as not publishable until commons_host_image returns its permanent Commons URL. Validation also
|
|
50287
|
+
catches missing source/body evidence, duplicate candidates, and unsupported placeholder sections.
|
|
49781
50288
|
- Create or edit a public wiki entity -> **commons_submit_entity**. This is a governed proposal write,
|
|
49782
|
-
not direct rendered HTML editing.
|
|
50289
|
+
not direct rendered HTML editing. Submit retains defensive auto-hosting for a stable direct public HTTPS image,
|
|
50290
|
+
but image ingress failure returns an actionable tool error: host different bytes or a different stable source,
|
|
50291
|
+
replace featuredImage.url, validate again, and retry the same intended write with the same idempotency key.
|
|
50292
|
+
Pick the closest entity type
|
|
49783
50293
|
first: SoftwareApplication, Organization, Person, Event, Place, Taxon, ScienceConcept, MathConcept, TechArticle,
|
|
49784
50294
|
Trail, or PublicArticle.
|
|
49785
50295
|
Creating a new entity costs 10 Credits; editing an existing entity costs 2 Credits. Preparation, validation,
|
|
@@ -51521,7 +52031,7 @@ var init_contracts = __esm({
|
|
|
51521
52031
|
});
|
|
51522
52032
|
|
|
51523
52033
|
// src/mcp/mcp-tool-schemas.ts
|
|
51524
|
-
var import_zod45, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, HarvestPaaHostedInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AnalyzeSiteSimilarityInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, SiteExportReadInputSchema, SiteExportImageInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LeadScalarSchema2, LeadRowSchema, LeadColumnMapSchema2, LeadRowsImportSourceSchema, LeadCsvTextImportSourceSchema, LeadUploadImportSourceSchema, LeadListUploadStartInputSchema, LeadListImportInputSchema, LeadRowsEnrichmentSourceSchema, ImportedLeadListSourceSchema, LeadListEnrichInputSchema, LeadListEnrichStatusInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsHostImageInputSchema, CommonsGetProposalInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomImageSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsUpdateEditorialArticleInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LeadSuggestedColumnOutputSchema, LeadColumnMapSuggestionOutputSchema, LeadArtifactOutputSchema, LeadListUploadStartOutputSchema, LeadListImportOutputSchema, LeadCandidateOutputSchema, LeadProgressOutputSchema, LeadBillingOutputSchema, LeadAssociatedPersonSourceOutputSchema, LeadAssociatedPersonOutputSchema, LeadSampleRowOutputSchema, LeadListEnrichmentOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, PageMediaAssetOutput, PageMediaArtifactOutput, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, SiteExportReadOutputSchema, SiteExportImageOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
52034
|
+
var import_zod45, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, HarvestPaaHostedInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AnalyzeSiteSimilarityInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, SiteExportReadInputSchema, SiteExportImageInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LeadScalarSchema2, LeadRowSchema, LeadColumnMapSchema2, LeadRowsImportSourceSchema, LeadCsvTextImportSourceSchema, LeadUploadImportSourceSchema, LeadListUploadStartInputSchema, LeadListImportInputSchema, LeadRowsEnrichmentSourceSchema, ImportedLeadListSourceSchema, LeadListEnrichInputSchema, LeadListEnrichStatusInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsHostImageInputSchema, CommonsGetProposalInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, CommonsFeaturedImageDiagnosticsOutputSchema, CommonsValidateEntityOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomImageSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsUpdateEditorialArticleInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LeadSuggestedColumnOutputSchema, LeadColumnMapSuggestionOutputSchema, LeadArtifactOutputSchema, LeadListUploadStartOutputSchema, LeadListImportOutputSchema, LeadCandidateOutputSchema, LeadProgressOutputSchema, LeadBillingOutputSchema, LeadAssociatedPersonSourceOutputSchema, LeadAssociatedPersonOutputSchema, LeadSampleRowOutputSchema, LeadListEnrichmentOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, PageMediaAssetOutput, PageMediaArtifactOutput, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, SiteExportReadOutputSchema, SiteExportImageOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
|
|
51525
52035
|
var init_mcp_tool_schemas = __esm({
|
|
51526
52036
|
"src/mcp/mcp-tool-schemas.ts"() {
|
|
51527
52037
|
"use strict";
|
|
@@ -51934,7 +52444,7 @@ var init_mcp_tool_schemas = __esm({
|
|
|
51934
52444
|
idOrSlug: import_zod45.z.string().trim().min(1).max(180).describe("Transparent Commons TPW-Q entity id or /wiki/ slug whose governed RFC 9264 linkset should be read.")
|
|
51935
52445
|
};
|
|
51936
52446
|
CommonsFeaturedImageInputSchema = import_zod45.z.object({
|
|
51937
|
-
url: import_zod45.z.string().url().describe("
|
|
52447
|
+
url: import_zod45.z.string().url().describe("For a publish-ready entity, use the permanent URL returned by commons_host_image. Submit can auto-host a stable direct public HTTPS image URL as a compatibility fallback, but validation reports any unregistered external URL as not ready. Do not use a chat attachment reference, caller-local path, temporary or signed URL, private URL, or HTML page URL."),
|
|
51938
52448
|
alt: import_zod45.z.string().trim().max(500).optional(),
|
|
51939
52449
|
caption: import_zod45.z.string().trim().max(1e3).optional(),
|
|
51940
52450
|
sourceUrl: import_zod45.z.string().url().optional(),
|
|
@@ -52026,14 +52536,14 @@ var init_mcp_tool_schemas = __esm({
|
|
|
52026
52536
|
maxCandidates: import_zod45.z.number().int().min(1).max(20).default(8).describe("Maximum duplicate candidates to return.")
|
|
52027
52537
|
};
|
|
52028
52538
|
CommonsSubmitEntityInputSchema = {
|
|
52029
|
-
idempotencyKey: import_zod45.z.string().trim().min(8).max(200).describe("Required unique opaque ID for this intended Commons write. Reuse
|
|
52539
|
+
idempotencyKey: import_zod45.z.string().trim().min(8).max(200).describe("Required unique opaque ID for this intended Commons write. Reuse it when retrying the same intended write after a timeout or after correcting a pre-persistence image-ingress failure; use a new value for each intentional create or edit."),
|
|
52030
52540
|
title: import_zod45.z.string().trim().min(3).max(180).describe("Public page title. This is also used for duplicate slug/entity checks when slug is omitted."),
|
|
52031
52541
|
description: import_zod45.z.string().trim().min(8).max(600).describe("Short article summary and schema.org description."),
|
|
52032
52542
|
slug: import_zod45.z.string().trim().max(180).optional().describe("Optional URL slug. Omit to derive one from title."),
|
|
52033
52543
|
entityId: import_zod45.z.string().trim().max(80).optional().describe("Existing Transparent Public Wiki entity id when proposing an edit. New entities normally omit this and receive a TPW-Q id."),
|
|
52034
52544
|
entityType: import_zod45.z.string().trim().max(120).default("PublicArticle").describe("Backend Wikidata-style type. Prefer precise entity classes such as SoftwareApplication, Organization, Person, Event, Place, Taxon, ScienceConcept, MathConcept, TechArticle, or PublicArticle; the public article structure should match the selected type."),
|
|
52035
52545
|
disambiguationName: import_zod45.z.string().trim().max(240).optional().describe("Clarifying name used when the concept could be confused with another entity."),
|
|
52036
|
-
featuredImage: CommonsFeaturedImageInputSchema.optional().describe("Required for auto-published public entities. The image is also added to the media manifest if absent."),
|
|
52546
|
+
featuredImage: CommonsFeaturedImageInputSchema.optional().describe("Required for auto-published public entities. First call commons_host_image and place its returned permanent URL here; validation does not fetch external images and reports unregistered URLs as not publishable. Submit retains a compatibility fallback that auto-hosts a stable direct public HTTPS image URL. The image is also added to the media manifest if absent."),
|
|
52037
52547
|
source: CommonsSourceInputSchema.optional().describe("Source provenance. Store original URL, source byline, and origin canonical here; canonical does not replace rights review."),
|
|
52038
52548
|
tags: import_zod45.z.array(import_zod45.z.string().trim().min(1).max(80)).max(24).optional().describe("Standardized topic tags. Use existing/searchable concepts when possible."),
|
|
52039
52549
|
keywords: import_zod45.z.array(import_zod45.z.string().trim().min(1).max(120)).max(50).optional().describe("SEO and retrieval keywords."),
|
|
@@ -52095,8 +52605,8 @@ var init_mcp_tool_schemas = __esm({
|
|
|
52095
52605
|
idOrSlug: import_zod45.z.string().trim().min(1).max(180).describe("Published entity id or /wiki/ slug whose contribution ledger should be read.")
|
|
52096
52606
|
};
|
|
52097
52607
|
CommonsHostImageInputSchema = {
|
|
52098
|
-
sourceUrl: import_zod45.z.string().url().optional().describe("
|
|
52099
|
-
imageBase64: import_zod45.z.string().min(16).optional().describe("Base64 image bytes for an image you already hold.
|
|
52608
|
+
sourceUrl: import_zod45.z.string().url().optional().describe("Stable direct public HTTPS URL whose response is the image bytes to host. Do not pass an HTML webpage, chat attachment reference, caller-local path, temporary or signed URL, or private/authenticated URL."),
|
|
52609
|
+
imageBase64: import_zod45.z.string().min(16).optional().describe("Base64 image bytes for an image you already hold, including forwarded chat attachment bytes. Prefer this over a temporary attachment URL when the serialized request remains under about 3 MB; larger files require a stable direct public HTTPS source URL."),
|
|
52100
52610
|
alt: import_zod45.z.string().trim().max(500).optional().describe("Alt text describing the image for readers who cannot see it."),
|
|
52101
52611
|
license: import_zod45.z.string().trim().max(240).optional().describe("License or usage terms of the original image, preserved with the hosted copy."),
|
|
52102
52612
|
attribution: import_zod45.z.string().trim().max(500).optional().describe("Credit line for the original photographer, publication, or archive.")
|
|
@@ -52128,6 +52638,30 @@ var init_mcp_tool_schemas = __esm({
|
|
|
52128
52638
|
error: import_zod45.z.string().optional(),
|
|
52129
52639
|
message: import_zod45.z.string().optional()
|
|
52130
52640
|
};
|
|
52641
|
+
CommonsFeaturedImageDiagnosticsOutputSchema = import_zod45.z.object({
|
|
52642
|
+
state: import_zod45.z.enum(["missing", "external_unhosted", "commons_hosted"]).describe("Storage-readiness state for the candidate featured image."),
|
|
52643
|
+
url: import_zod45.z.string().url().nullable().describe("Normalized candidate featured-image URL, or null when none was supplied."),
|
|
52644
|
+
commonsImageId: import_zod45.z.string().nullable().describe("Registered Commons image ID when metadata proves the image is hosted, otherwise null."),
|
|
52645
|
+
readyForPublish: import_zod45.z.boolean().describe("Whether Commons storage metadata proves this featured image is ready to publish."),
|
|
52646
|
+
submitWillAttemptAutoHost: import_zod45.z.boolean().describe("Whether submit will use its compatibility fallback to try hosting this external image."),
|
|
52647
|
+
requiredAction: import_zod45.z.string().nullable().describe("Action the caller must take before submit, or null when the image is ready.")
|
|
52648
|
+
}).describe("Featured-image storage readiness determined without fetching or storing external bytes.");
|
|
52649
|
+
CommonsValidateEntityOutputSchema = {
|
|
52650
|
+
ok: import_zod45.z.boolean(),
|
|
52651
|
+
data: import_zod45.z.object({
|
|
52652
|
+
ok: import_zod45.z.literal(true),
|
|
52653
|
+
valid: import_zod45.z.boolean(),
|
|
52654
|
+
publishable: import_zod45.z.boolean(),
|
|
52655
|
+
autoPublishEligible: import_zod45.z.boolean(),
|
|
52656
|
+
errors: import_zod45.z.array(import_zod45.z.string()),
|
|
52657
|
+
warnings: import_zod45.z.array(import_zod45.z.string()),
|
|
52658
|
+
imageDiagnostics: import_zod45.z.object({
|
|
52659
|
+
featuredImage: CommonsFeaturedImageDiagnosticsOutputSchema
|
|
52660
|
+
}).describe("Read-only image readiness and recovery guidance for this payload.")
|
|
52661
|
+
}).passthrough().optional(),
|
|
52662
|
+
error: import_zod45.z.string().optional(),
|
|
52663
|
+
message: import_zod45.z.string().optional()
|
|
52664
|
+
};
|
|
52131
52665
|
DirectoryWorkflowStatusInputSchema = {
|
|
52132
52666
|
jobId: import_zod45.z.string().trim().min(1).describe("The jobId returned by directory_workflow. Poll until status is complete, partial, empty, or failed.")
|
|
52133
52667
|
};
|
|
@@ -54839,11 +55373,11 @@ function requireTasksCapability(capabilityValue) {
|
|
|
54839
55373
|
);
|
|
54840
55374
|
}
|
|
54841
55375
|
function taskKey(secret2) {
|
|
54842
|
-
return (0,
|
|
55376
|
+
return (0, import_node_crypto34.createHash)("sha256").update("mcp-scraper-task-handle\0", "utf8").update(secret2, "utf8").digest();
|
|
54843
55377
|
}
|
|
54844
55378
|
function encodeTaskHandle(payload, secret2) {
|
|
54845
|
-
const nonce = (0,
|
|
54846
|
-
const cipher = (0,
|
|
55379
|
+
const nonce = (0, import_node_crypto34.randomBytes)(12);
|
|
55380
|
+
const cipher = (0, import_node_crypto34.createCipheriv)("aes-256-gcm", taskKey(secret2), nonce);
|
|
54847
55381
|
const ciphertext = Buffer.concat([
|
|
54848
55382
|
cipher.update(JSON.stringify(payload), "utf8"),
|
|
54849
55383
|
cipher.final()
|
|
@@ -54860,7 +55394,7 @@ function decodeTaskHandle(taskId, secret2, ownerId2) {
|
|
|
54860
55394
|
const nonce = bytes.subarray(0, 12);
|
|
54861
55395
|
const tag = bytes.subarray(bytes.length - 16);
|
|
54862
55396
|
const ciphertext = bytes.subarray(12, bytes.length - 16);
|
|
54863
|
-
const decipher = (0,
|
|
55397
|
+
const decipher = (0, import_node_crypto34.createDecipheriv)("aes-256-gcm", taskKey(secret2), nonce);
|
|
54864
55398
|
decipher.setAuthTag(tag);
|
|
54865
55399
|
const parsed = JSON.parse(Buffer.concat([
|
|
54866
55400
|
decipher.update(ciphertext),
|
|
@@ -55224,12 +55758,12 @@ async function handleMcpTasksHttpRequest(request, executor, options) {
|
|
|
55224
55758
|
return taskHttpError(id, error instanceof import_server.ProtocolError ? error : new import_server.ProtocolError(-32603, error instanceof Error ? error.message : "Internal error"));
|
|
55225
55759
|
}
|
|
55226
55760
|
}
|
|
55227
|
-
var import_server,
|
|
55761
|
+
var import_server, import_node_crypto34, import_zod46, MCP_TASKS_EXTENSION_ID, TASK_HANDLE_VERSION, TASK_TTL_MS, TASK_POLL_INTERVAL_MS, TASK_INVALID_PARAMS, TASK_MISSING_CAPABILITY, TASK_START_TOOL_NAMES;
|
|
55228
55762
|
var init_mcp_tasks_extension = __esm({
|
|
55229
55763
|
"src/mcp/mcp-tasks-extension.ts"() {
|
|
55230
55764
|
"use strict";
|
|
55231
55765
|
import_server = require("@modelcontextprotocol/server");
|
|
55232
|
-
|
|
55766
|
+
import_node_crypto34 = require("crypto");
|
|
55233
55767
|
import_zod46 = require("zod");
|
|
55234
55768
|
init_mcp_tool_schemas();
|
|
55235
55769
|
MCP_TASKS_EXTENSION_ID = "io.modelcontextprotocol/tasks";
|
|
@@ -55537,7 +56071,7 @@ var init_analytics_mcp_tools = __esm({
|
|
|
55537
56071
|
|
|
55538
56072
|
// src/mcp/paa-mcp-server.ts
|
|
55539
56073
|
function hashOwnerId(callerKey) {
|
|
55540
|
-
return (0,
|
|
56074
|
+
return (0, import_node_crypto35.createHash)("sha256").update(callerKey).digest("hex").slice(0, 24);
|
|
55541
56075
|
}
|
|
55542
56076
|
function liveWebToolAnnotations(title) {
|
|
55543
56077
|
return {
|
|
@@ -56024,9 +56558,9 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
56024
56558
|
}, async (input) => executor.commonsPrepareEntity(input));
|
|
56025
56559
|
server.registerTool("commons_validate_entity", {
|
|
56026
56560
|
title: "Transparent Commons Validate Entity",
|
|
56027
|
-
description: "
|
|
56561
|
+
description: "Read-only validation for a proposed Transparent Commons entity payload. Call it after commons_prepare_entity, composing the page, and commons_host_image. It does not fetch or store image bytes: an external or otherwise unregistered featured image remains not publishable until commons_host_image returns the permanent Commons URL. Inspect imageDiagnostics for readiness and the required action before commons_submit_entity. Also checks source/body evidence, existing-entity conflict state, heading profile alignment, and unsupported placeholder sections.",
|
|
56028
56562
|
inputSchema: CommonsValidateEntityInputSchema,
|
|
56029
|
-
outputSchema: recordOutputSchema("commons_validate_entity",
|
|
56563
|
+
outputSchema: recordOutputSchema("commons_validate_entity", CommonsValidateEntityOutputSchema),
|
|
56030
56564
|
annotations: {
|
|
56031
56565
|
title: "Transparent Commons Validate Entity",
|
|
56032
56566
|
readOnlyHint: true,
|
|
@@ -56037,7 +56571,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
56037
56571
|
}, async (input) => executor.commonsValidateEntity(input));
|
|
56038
56572
|
server.registerTool("commons_submit_entity", {
|
|
56039
56573
|
title: "Transparent Commons Governed Entity Write",
|
|
56040
|
-
description: "
|
|
56574
|
+
description: "Charged governed write that creates or proposes an edit to a Transparent Commons public wiki entity. A new entity costs 10 Credits; an edit costs 2 Credits. Preparation, image hosting, and validation are free, and idempotent retries are not charged twice. Normal workflow is commons_prepare_entity, compose the page, commons_host_image, commons_validate_entity, then submit with the returned permanent featuredImage.url. Submit retains a compatibility fallback that auto-hosts a stable direct public HTTPS image URL; if image ingress fails, it returns an actionable image tool error so you can host different bytes or a different stable source, replace the URL, validate again, and retry the same intended write with the same idempotencyKey. This never edits rendered HTML directly. Transparent Commons is an open wiki: any account may edit any entity, and every applied edit is recorded on the public contribution ledger. Publishing requires a ready featured image and body/source evidence. Pass baseRevision when editing so the ledger can show whether the edit was written on top of a newer revision. Requires idempotencyKey.",
|
|
56041
56575
|
inputSchema: CommonsSubmitEntityInputSchema,
|
|
56042
56576
|
outputSchema: recordOutputSchema("commons_submit_entity", CommonsGenericOutputSchema),
|
|
56043
56577
|
annotations: {
|
|
@@ -56063,7 +56597,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
56063
56597
|
}, async (input) => executor.commonsGetEntityLedger(input));
|
|
56064
56598
|
server.registerTool("commons_host_image", {
|
|
56065
56599
|
title: "Host a Transparent Commons Image",
|
|
56066
|
-
description: "
|
|
56600
|
+
description: "Normal prerequisite for any featured image whose URL was not already returned by commons_host_image. Host image bytes from imageBase64 when you already have an attachment and the serialized request stays under about 3 MB, or from a stable direct public HTTPS image URL; do not pass a webpage, caller-local path, private URL, or temporary/signed attachment URL. Returns the permanent Commons URL to place in featuredImage.url before commons_validate_entity and commons_submit_entity. Submit can still auto-host a stable public source as a compatibility fallback. JPEG, PNG, GIF, and WebP are accepted up to 10 MB; SVG is rejected. Identical bytes are stored once.",
|
|
56067
56601
|
inputSchema: CommonsHostImageInputSchema,
|
|
56068
56602
|
outputSchema: recordOutputSchema("commons_host_image", CommonsGenericOutputSchema),
|
|
56069
56603
|
annotations: {
|
|
@@ -56525,7 +57059,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
56525
57059
|
annotations: { title: "Set Scheduled Action Connections", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
56526
57060
|
}, async (input) => executor.setScheduledActionConnections(input));
|
|
56527
57061
|
}
|
|
56528
|
-
var import_server2, import_zod48, import_node_fs11, import_node_path17,
|
|
57062
|
+
var import_server2, import_zod48, import_node_fs11, import_node_path17, import_node_crypto35, ACTION_CONFIRMATION_SCHEMA;
|
|
56529
57063
|
var init_paa_mcp_server = __esm({
|
|
56530
57064
|
"src/mcp/paa-mcp-server.ts"() {
|
|
56531
57065
|
"use strict";
|
|
@@ -56533,7 +57067,7 @@ var init_paa_mcp_server = __esm({
|
|
|
56533
57067
|
import_zod48 = require("zod");
|
|
56534
57068
|
import_node_fs11 = require("fs");
|
|
56535
57069
|
import_node_path17 = require("path");
|
|
56536
|
-
|
|
57070
|
+
import_node_crypto35 = require("crypto");
|
|
56537
57071
|
init_version();
|
|
56538
57072
|
init_rates();
|
|
56539
57073
|
init_mcp_response_formatter();
|
|
@@ -56618,7 +57152,8 @@ function httpErrorPayload(path6, res, data) {
|
|
|
56618
57152
|
const safeCode = privateUpstreamState ? "service_unavailable" : recognized ? candidateCode : normalizePublicErrorCode(candidateCode);
|
|
56619
57153
|
const bodyMessage = objectData ? objectData.message ?? objectData.error ?? rawCode : data;
|
|
56620
57154
|
return {
|
|
56621
|
-
...recognized && objectData ? objectData : {},
|
|
57155
|
+
...recognized && objectData && safeCode !== "mcp_request_timeout" ? objectData : {},
|
|
57156
|
+
...recognized ? { code: safeCode } : {},
|
|
56622
57157
|
error: safeCode,
|
|
56623
57158
|
error_code: safeCode,
|
|
56624
57159
|
error_type: recognized && typeof objectData?.error_type === "string" ? objectData.error_type : "http",
|
|
@@ -56626,7 +57161,7 @@ function httpErrorPayload(path6, res, data) {
|
|
|
56626
57161
|
status: res.status,
|
|
56627
57162
|
statusText: res.statusText,
|
|
56628
57163
|
path: path6,
|
|
56629
|
-
message: recognized && typeof bodyMessage === "string" && bodyMessage.trim() ? sanitizeVendorName(bodyMessage) : publicErrorMessage(safeCode)
|
|
57164
|
+
message: safeCode === "mcp_request_timeout" ? "The connected service operation timed out before returning a result. Retry failed items or use a smaller batch." : recognized && typeof bodyMessage === "string" && bodyMessage.trim() ? sanitizeVendorName(bodyMessage) : publicErrorMessage(safeCode)
|
|
56630
57165
|
};
|
|
56631
57166
|
}
|
|
56632
57167
|
function withDefaultHostedProfile(input) {
|
|
@@ -56654,11 +57189,11 @@ function analyticsReportPath(input, report) {
|
|
|
56654
57189
|
const suffix2 = query.size ? `?${query.toString()}` : "";
|
|
56655
57190
|
return `/analytics/sites/${encodeURIComponent(input.siteId)}/${report}${suffix2}`;
|
|
56656
57191
|
}
|
|
56657
|
-
var
|
|
57192
|
+
var import_node_crypto36, HttpMcpToolExecutor;
|
|
56658
57193
|
var init_http_mcp_tool_executor = __esm({
|
|
56659
57194
|
"src/mcp/http-mcp-tool-executor.ts"() {
|
|
56660
57195
|
"use strict";
|
|
56661
|
-
|
|
57196
|
+
import_node_crypto36 = require("crypto");
|
|
56662
57197
|
init_harvest_timeout();
|
|
56663
57198
|
init_browser_service_env();
|
|
56664
57199
|
init_errors();
|
|
@@ -56727,13 +57262,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
56727
57262
|
});
|
|
56728
57263
|
}
|
|
56729
57264
|
async callDirectoryWorkflowStart(body, explicitIdempotencyKey) {
|
|
56730
|
-
const idempotencyKey4 = `mcp-directory-${(0,
|
|
57265
|
+
const idempotencyKey4 = `mcp-directory-${(0, import_node_crypto36.createHash)("sha256").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56731
57266
|
return this.call("/directory/run", body, this.timeoutMs, "POST", {
|
|
56732
57267
|
"Idempotency-Key": idempotencyKey4
|
|
56733
57268
|
});
|
|
56734
57269
|
}
|
|
56735
57270
|
async callSiteExtractStart(toolName, body, explicitIdempotencyKey) {
|
|
56736
|
-
const idempotencyKey4 = `mcp-site-${(0,
|
|
57271
|
+
const idempotencyKey4 = `mcp-site-${(0, import_node_crypto36.createHash)("sha256").update(toolName).update("\0").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56737
57272
|
return this.call("/extract-site", body, this.timeoutMs, "POST", {
|
|
56738
57273
|
"Idempotency-Key": idempotencyKey4
|
|
56739
57274
|
});
|
|
@@ -57177,7 +57712,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57177
57712
|
report: input.report,
|
|
57178
57713
|
format: input.format
|
|
57179
57714
|
}, this.timeoutMs, "POST", {
|
|
57180
|
-
"Idempotency-Key": `analytics-export-${(0,
|
|
57715
|
+
"Idempotency-Key": `analytics-export-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57181
57716
|
});
|
|
57182
57717
|
}
|
|
57183
57718
|
commonsSearchEntities(input) {
|
|
@@ -57216,7 +57751,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57216
57751
|
commonsSubmitEntity(input) {
|
|
57217
57752
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57218
57753
|
return this.call("/commons/entities/propose", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57219
|
-
"Idempotency-Key": `commons-${(0,
|
|
57754
|
+
"Idempotency-Key": `commons-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57220
57755
|
});
|
|
57221
57756
|
}
|
|
57222
57757
|
commonsGetEntityLedger(input) {
|
|
@@ -57231,7 +57766,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57231
57766
|
commonsUpdateEditorialArticle(input) {
|
|
57232
57767
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57233
57768
|
return this.call("/commons/publications/articles", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57234
|
-
"Idempotency-Key": `commons-article-${(0,
|
|
57769
|
+
"Idempotency-Key": `commons-article-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57235
57770
|
});
|
|
57236
57771
|
}
|
|
57237
57772
|
commonsSaveFilter(input) {
|
|
@@ -57252,13 +57787,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57252
57787
|
commonsClaimPublication(input) {
|
|
57253
57788
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57254
57789
|
return this.call("/commons/publications/claim", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57255
|
-
"Idempotency-Key": `commons-publication-claim-${(0,
|
|
57790
|
+
"Idempotency-Key": `commons-publication-claim-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57256
57791
|
});
|
|
57257
57792
|
}
|
|
57258
57793
|
commonsPublishEditorial(input) {
|
|
57259
57794
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57260
57795
|
return this.call("/commons/publications/publish", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57261
|
-
"Idempotency-Key": `commons-publication-publish-${(0,
|
|
57796
|
+
"Idempotency-Key": `commons-publication-publish-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57262
57797
|
});
|
|
57263
57798
|
}
|
|
57264
57799
|
commonsGetPublication(input) {
|
|
@@ -57266,13 +57801,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57266
57801
|
return this.getJson(input.subdomain ? `/commons/publications/${encodeURIComponent(input.subdomain)}?${query}` : `/commons/publications/me?${query}`);
|
|
57267
57802
|
}
|
|
57268
57803
|
async captureSerpSnapshot(input) {
|
|
57269
|
-
const fingerprint2 = (0,
|
|
57804
|
+
const fingerprint2 = (0, import_node_crypto36.createHash)("sha256").update(JSON.stringify(input)).digest("hex");
|
|
57270
57805
|
const now = Date.now();
|
|
57271
57806
|
for (const [pendingFingerprint, pendingEntry] of this.pendingSerpCaptureBillingKeys) {
|
|
57272
57807
|
if (pendingEntry.expiresAt <= now) this.pendingSerpCaptureBillingKeys.delete(pendingFingerprint);
|
|
57273
57808
|
}
|
|
57274
57809
|
const pending = this.pendingSerpCaptureBillingKeys.get(fingerprint2);
|
|
57275
|
-
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0,
|
|
57810
|
+
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0, import_node_crypto36.randomUUID)();
|
|
57276
57811
|
this.pendingSerpCaptureBillingKeys.set(fingerprint2, {
|
|
57277
57812
|
key: idempotencyKey4,
|
|
57278
57813
|
expiresAt: now + 15 * 6e4
|
|
@@ -63282,7 +63817,7 @@ async function createImageSourceArtifact(args) {
|
|
|
63282
63817
|
if (args.content.length === 0 || args.content.length > IMAGE_SOURCE_MAX_BYTES) {
|
|
63283
63818
|
throw new Error("image_source_size_invalid");
|
|
63284
63819
|
}
|
|
63285
|
-
const id = (0,
|
|
63820
|
+
const id = (0, import_node_crypto37.randomUUID)().replaceAll("-", "");
|
|
63286
63821
|
return createPrivateArtifact({
|
|
63287
63822
|
policy: policy4(),
|
|
63288
63823
|
ownerId: args.ownerId,
|
|
@@ -63301,11 +63836,11 @@ async function readOwnedImageSourceArtifact(args) {
|
|
|
63301
63836
|
maxBytes: IMAGE_SOURCE_MAX_BYTES
|
|
63302
63837
|
});
|
|
63303
63838
|
}
|
|
63304
|
-
var
|
|
63839
|
+
var import_node_crypto37, IMAGE_SOURCE_ARTIFACT_PREFIX, IMAGE_SOURCE_ARTIFACT_TTL_MS, IMAGE_SOURCE_DOWNLOAD_TTL_MS, IMAGE_SOURCE_MAX_BYTES, ALLOWED_IMAGE_TYPES;
|
|
63305
63840
|
var init_image_source_artifacts = __esm({
|
|
63306
63841
|
"src/api/image-source-artifacts.ts"() {
|
|
63307
63842
|
"use strict";
|
|
63308
|
-
|
|
63843
|
+
import_node_crypto37 = require("crypto");
|
|
63309
63844
|
init_private_artifacts();
|
|
63310
63845
|
IMAGE_SOURCE_ARTIFACT_PREFIX = "image-sources/";
|
|
63311
63846
|
IMAGE_SOURCE_ARTIFACT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -64919,7 +65454,7 @@ async function runBrowserAgentMigration() {
|
|
|
64919
65454
|
}
|
|
64920
65455
|
async function createExtensionRow(input) {
|
|
64921
65456
|
const db = getDb();
|
|
64922
|
-
const id = `bext_${(0,
|
|
65457
|
+
const id = `bext_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
64923
65458
|
await db.execute({
|
|
64924
65459
|
sql: `INSERT INTO browser_agent_extensions (id, user_id, name, backend_id, backend_name, source, source_url, size_bytes)
|
|
64925
65460
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -64954,7 +65489,7 @@ async function deleteExtensionRow(userId, name) {
|
|
|
64954
65489
|
}
|
|
64955
65490
|
async function createAuthConnectionRow(input) {
|
|
64956
65491
|
const db = getDb();
|
|
64957
|
-
const connectionId = `authc_${(0,
|
|
65492
|
+
const connectionId = `authc_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
64958
65493
|
await db.execute({
|
|
64959
65494
|
sql: `INSERT INTO browser_auth_connections (connection_id, domain, profile, account_email, note, status, browser_agent_session_id)
|
|
64960
65495
|
VALUES (?, ?, ?, ?, ?, 'NEEDS_AUTH', ?)`,
|
|
@@ -65039,7 +65574,7 @@ async function deleteProfileLabel(userId, profile) {
|
|
|
65039
65574
|
}
|
|
65040
65575
|
async function createSessionRow(input) {
|
|
65041
65576
|
const db = getDb();
|
|
65042
|
-
const id = `bas_${(0,
|
|
65577
|
+
const id = `bas_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
65043
65578
|
await db.execute({
|
|
65044
65579
|
sql: `INSERT INTO browser_agent_sessions (id, runtime_session_id, live_view_url, cdp_ws_url, status, label, user_id, concurrency_lock_id, last_action_at)
|
|
65045
65580
|
VALUES (?, ?, ?, ?, 'open', ?, ?, ?, datetime('now'))`,
|
|
@@ -65116,7 +65651,7 @@ async function recordAction(input) {
|
|
|
65116
65651
|
sql: `INSERT INTO browser_agent_actions (id, session_id, type, params_json, ok, error)
|
|
65117
65652
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
65118
65653
|
args: [
|
|
65119
|
-
`baa_${(0,
|
|
65654
|
+
`baa_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`,
|
|
65120
65655
|
input.sessionId,
|
|
65121
65656
|
input.type,
|
|
65122
65657
|
input.params == null ? null : JSON.stringify(input.params),
|
|
@@ -65156,11 +65691,11 @@ async function listReplayRows(sessionId) {
|
|
|
65156
65691
|
});
|
|
65157
65692
|
return res.rows;
|
|
65158
65693
|
}
|
|
65159
|
-
var
|
|
65694
|
+
var import_node_crypto38, _ready2, _migrationPromise2, ORPHANED_SESSION_STATUS;
|
|
65160
65695
|
var init_browser_agent_db = __esm({
|
|
65161
65696
|
"src/api/browser-agent-db.ts"() {
|
|
65162
65697
|
"use strict";
|
|
65163
|
-
|
|
65698
|
+
import_node_crypto38 = require("crypto");
|
|
65164
65699
|
init_db();
|
|
65165
65700
|
_ready2 = false;
|
|
65166
65701
|
_migrationPromise2 = null;
|
|
@@ -66302,7 +66837,7 @@ var init_browser_agent_service = __esm({
|
|
|
66302
66837
|
|
|
66303
66838
|
// src/api/serp-identity-db.ts
|
|
66304
66839
|
async function createSerpIdentityRow(input) {
|
|
66305
|
-
const id = `serpi_${(0,
|
|
66840
|
+
const id = `serpi_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
66306
66841
|
await getDb().execute({
|
|
66307
66842
|
sql: `INSERT INTO serp_identities
|
|
66308
66843
|
(id, user_id, name, kernel_profile_name, kernel_proxy_id, proxy_type, country, status)
|
|
@@ -66347,11 +66882,11 @@ async function deleteSerpIdentityRow(userId, name) {
|
|
|
66347
66882
|
args: [userId, name]
|
|
66348
66883
|
});
|
|
66349
66884
|
}
|
|
66350
|
-
var
|
|
66885
|
+
var import_node_crypto39;
|
|
66351
66886
|
var init_serp_identity_db = __esm({
|
|
66352
66887
|
"src/api/serp-identity-db.ts"() {
|
|
66353
66888
|
"use strict";
|
|
66354
|
-
|
|
66889
|
+
import_node_crypto39 = require("crypto");
|
|
66355
66890
|
init_db();
|
|
66356
66891
|
}
|
|
66357
66892
|
});
|
|
@@ -66363,8 +66898,8 @@ function kernelClient() {
|
|
|
66363
66898
|
return new import_sdk10.default({ apiKey });
|
|
66364
66899
|
}
|
|
66365
66900
|
function backendName(userId, name, resource) {
|
|
66366
|
-
const digest2 = (0,
|
|
66367
|
-
const nonce = (0,
|
|
66901
|
+
const digest2 = (0, import_node_crypto40.createHash)("sha256").update(`${userId}:${name}`).digest("hex").slice(0, 16);
|
|
66902
|
+
const nonce = (0, import_node_crypto40.randomUUID)().replace(/-/g, "").slice(0, 8);
|
|
66368
66903
|
return `mcp-serp-${resource}-${digest2}-${nonce}`;
|
|
66369
66904
|
}
|
|
66370
66905
|
function isNotFound2(error) {
|
|
@@ -66442,11 +66977,11 @@ async function deleteSerpIdentity(userId, name) {
|
|
|
66442
66977
|
throw error;
|
|
66443
66978
|
}
|
|
66444
66979
|
}
|
|
66445
|
-
var
|
|
66980
|
+
var import_node_crypto40, import_sdk10, MAX_SERP_IDENTITIES_PER_USER;
|
|
66446
66981
|
var init_serp_identity_service = __esm({
|
|
66447
66982
|
"src/api/serp-identity-service.ts"() {
|
|
66448
66983
|
"use strict";
|
|
66449
|
-
|
|
66984
|
+
import_node_crypto40 = require("crypto");
|
|
66450
66985
|
import_sdk10 = __toESM(require("@onkernel/sdk"), 1);
|
|
66451
66986
|
init_browser_service_env();
|
|
66452
66987
|
init_serp_identity_db();
|
|
@@ -67157,7 +67692,7 @@ function buildBrowserAgentRoutes() {
|
|
|
67157
67692
|
}
|
|
67158
67693
|
const existing = await getExtensionRow(user.id, name);
|
|
67159
67694
|
if (existing) return c.json({ error: `an extension named "${name}" already exists \u2014 delete it first or pick another name` }, 409);
|
|
67160
|
-
const backendName2 = `u${user.id}_${(0,
|
|
67695
|
+
const backendName2 = `u${user.id}_${(0, import_node_crypto41.randomUUID)().replace(/-/g, "")}`;
|
|
67161
67696
|
try {
|
|
67162
67697
|
const imported = await importExtensionFromStore(storeUrl, backendName2);
|
|
67163
67698
|
const row = await createExtensionRow({
|
|
@@ -67216,11 +67751,11 @@ function buildBrowserAgentRoutes() {
|
|
|
67216
67751
|
});
|
|
67217
67752
|
return app2;
|
|
67218
67753
|
}
|
|
67219
|
-
var
|
|
67754
|
+
var import_node_crypto41, import_hono24, auth, DEFAULT_BROWSER_SESSION_LOCK_TTL_SECONDS, EXTENSION_NAME_RE, SERP_IDENTITY_NAME_RE;
|
|
67220
67755
|
var init_browser_agent_routes = __esm({
|
|
67221
67756
|
"src/api/browser-agent-routes.ts"() {
|
|
67222
67757
|
"use strict";
|
|
67223
|
-
|
|
67758
|
+
import_node_crypto41 = require("crypto");
|
|
67224
67759
|
import_hono24 = require("hono");
|
|
67225
67760
|
init_api_auth();
|
|
67226
67761
|
init_errors();
|
|
@@ -67778,7 +68313,7 @@ async function getKeys() {
|
|
|
67778
68313
|
const privateKey = await (0, import_jose2.importPKCS8)(pem, "RS256", { extractable: true });
|
|
67779
68314
|
const full = await (0, import_jose2.exportJWK)(privateKey);
|
|
67780
68315
|
const publicJwk = { kty: full.kty, n: full.n, e: full.e };
|
|
67781
|
-
const kid = (0,
|
|
68316
|
+
const kid = (0, import_node_crypto42.createHash)("sha256").update(JSON.stringify({ e: publicJwk.e, kty: publicJwk.kty, n: publicJwk.n })).digest("base64url").slice(0, 16);
|
|
67782
68317
|
publicJwk.kid = kid;
|
|
67783
68318
|
publicJwk.alg = "RS256";
|
|
67784
68319
|
publicJwk.use = "sig";
|
|
@@ -67957,23 +68492,23 @@ async function validateAuthRequest(p) {
|
|
|
67957
68492
|
}
|
|
67958
68493
|
function pkceMatches(verifier, challenge) {
|
|
67959
68494
|
if (!verifier) return false;
|
|
67960
|
-
const computed = (0,
|
|
68495
|
+
const computed = (0, import_node_crypto42.createHash)("sha256").update(verifier).digest("base64url");
|
|
67961
68496
|
return computed === challenge;
|
|
67962
68497
|
}
|
|
67963
68498
|
async function mintAccessToken(identity, scope, plan, audience) {
|
|
67964
68499
|
const { privateKey, kid } = await getKeys();
|
|
67965
|
-
return new import_jose2.SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti((0,
|
|
68500
|
+
return new import_jose2.SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti((0, import_node_crypto42.randomUUID)()).setExpirationTime(`${ACCESS_TTL_SECONDS}s`).sign(privateKey);
|
|
67966
68501
|
}
|
|
67967
68502
|
function tokenErrorResponse(c, error, description, status) {
|
|
67968
68503
|
return c.json({ error, error_description: description }, status);
|
|
67969
68504
|
}
|
|
67970
|
-
var import_hono26, import_cookie,
|
|
68505
|
+
var import_hono26, import_cookie, import_node_crypto42, import_jose2, ISSUER, RESOURCE, SCRAPER_RESOURCE, MEMORY_SCOPES, SCRAPER_SCOPES, SUPPORTED_SCOPES, ACCESS_TTL_SECONDS, REFRESH_TTL_SECONDS, CODE_TTL_SECONDS, ROTATION_GRACE_SECONDS, OAUTH_DATABASE_TIMEOUT_MS, OAuthDatabaseUnavailableError, secureCookies, sessionCookieOptions, cachedKeys, oauthApp;
|
|
67971
68506
|
var init_oauth_routes = __esm({
|
|
67972
68507
|
"src/api/oauth-routes.ts"() {
|
|
67973
68508
|
"use strict";
|
|
67974
68509
|
import_hono26 = require("hono");
|
|
67975
68510
|
import_cookie = require("hono/cookie");
|
|
67976
|
-
|
|
68511
|
+
import_node_crypto42 = require("crypto");
|
|
67977
68512
|
import_jose2 = require("jose");
|
|
67978
68513
|
init_session();
|
|
67979
68514
|
init_db();
|
|
@@ -68080,7 +68615,7 @@ var init_oauth_routes = __esm({
|
|
|
68080
68615
|
}
|
|
68081
68616
|
}
|
|
68082
68617
|
const clientName = typeof body.client_name === "string" ? body.client_name : null;
|
|
68083
|
-
const clientId = `client_${(0,
|
|
68618
|
+
const clientId = `client_${(0, import_node_crypto42.randomBytes)(16).toString("hex")}`;
|
|
68084
68619
|
await withOAuthDatabaseDeadline("register-client", registerClient(clientId, redirectUris, clientName));
|
|
68085
68620
|
console.log("[oauth-dcr] register OK client_id=%s redirect_uris=%s", clientId, JSON.stringify(redirectUris));
|
|
68086
68621
|
return c.json({
|
|
@@ -68133,7 +68668,7 @@ var init_oauth_routes = __esm({
|
|
|
68133
68668
|
if (action3 === "deny") return redirectWithError(p.redirect_uri, p.state, "access_denied");
|
|
68134
68669
|
if (action3 !== "approve") return c.text("unsupported action", 400);
|
|
68135
68670
|
const scope = negotiateScope(p.scope, user, p.resource);
|
|
68136
|
-
const code = `code_${(0,
|
|
68671
|
+
const code = `code_${(0, import_node_crypto42.randomBytes)(32).toString("base64url")}`;
|
|
68137
68672
|
const expiresAt = new Date(Date.now() + CODE_TTL_SECONDS * 1e3).toISOString();
|
|
68138
68673
|
await withOAuthDatabaseDeadline("put-authorization-code", putCode({
|
|
68139
68674
|
code,
|
|
@@ -68172,7 +68707,7 @@ var init_oauth_routes = __esm({
|
|
|
68172
68707
|
const plan = user ? resolvePlan(user) : "free";
|
|
68173
68708
|
const audience = record.resource ?? RESOURCE();
|
|
68174
68709
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
68175
|
-
const refreshToken = `rt_${(0,
|
|
68710
|
+
const refreshToken = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
68176
68711
|
await withOAuthDatabaseDeadline("put-refresh-token", putRefresh({
|
|
68177
68712
|
refresh_token: refreshToken,
|
|
68178
68713
|
client_id: clientId,
|
|
@@ -68202,7 +68737,7 @@ var init_oauth_routes = __esm({
|
|
|
68202
68737
|
const plan = user ? resolvePlan(user) : "free";
|
|
68203
68738
|
const audience = record.resource ?? RESOURCE();
|
|
68204
68739
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
68205
|
-
const nextRefresh = `rt_${(0,
|
|
68740
|
+
const nextRefresh = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
68206
68741
|
await withOAuthDatabaseDeadline("rotate-refresh-token", rotateRefresh(refreshToken, {
|
|
68207
68742
|
refresh_token: nextRefresh,
|
|
68208
68743
|
client_id: record.client_id,
|
|
@@ -69622,7 +70157,7 @@ function quoteUntrusted(value) {
|
|
|
69622
70157
|
return clean3.split("\n").map((line) => `> ${line}`).join("\n");
|
|
69623
70158
|
}
|
|
69624
70159
|
function shortHash(value, length = 24) {
|
|
69625
|
-
return (0,
|
|
70160
|
+
return (0, import_node_crypto43.createHash)("sha256").update(value).digest("hex").slice(0, length);
|
|
69626
70161
|
}
|
|
69627
70162
|
function safePathPart(value) {
|
|
69628
70163
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "contact";
|
|
@@ -70110,11 +70645,11 @@ async function captureSupportMessage(memoryKey, email, options) {
|
|
|
70110
70645
|
direction: options.direction
|
|
70111
70646
|
};
|
|
70112
70647
|
}
|
|
70113
|
-
var
|
|
70648
|
+
var import_node_crypto43, SUPPORT_TAGS, ISSUE_TAGS;
|
|
70114
70649
|
var init_resend_support_thread = __esm({
|
|
70115
70650
|
"src/api/resend-support-thread.ts"() {
|
|
70116
70651
|
"use strict";
|
|
70117
|
-
|
|
70652
|
+
import_node_crypto43 = require("crypto");
|
|
70118
70653
|
init_memory();
|
|
70119
70654
|
SUPPORT_TAGS = [
|
|
70120
70655
|
{
|
|
@@ -70699,7 +71234,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
70699
71234
|
) < ?
|
|
70700
71235
|
`,
|
|
70701
71236
|
args: [
|
|
70702
|
-
(0,
|
|
71237
|
+
(0, import_node_crypto44.randomUUID)(),
|
|
70703
71238
|
input.eventSlug,
|
|
70704
71239
|
input.email,
|
|
70705
71240
|
input.firstName,
|
|
@@ -70716,7 +71251,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
70716
71251
|
id, event_slug, email, first_name, last_name, status
|
|
70717
71252
|
) VALUES (?, ?, ?, ?, ?, 'waitlisted')
|
|
70718
71253
|
`,
|
|
70719
|
-
args: [(0,
|
|
71254
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
70720
71255
|
});
|
|
70721
71256
|
const waitlisted = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
70722
71257
|
if (!waitlisted) throw new Error("workshop registration could not be claimed");
|
|
@@ -70731,7 +71266,7 @@ async function registerWorkshopInterest(input) {
|
|
|
70731
71266
|
id, event_slug, email, first_name, last_name, status
|
|
70732
71267
|
) VALUES (?, ?, ?, ?, ?, 'interested')
|
|
70733
71268
|
`,
|
|
70734
|
-
args: [(0,
|
|
71269
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
70735
71270
|
});
|
|
70736
71271
|
const registration = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
70737
71272
|
if (!registration) throw new Error("workshop interest could not be recorded");
|
|
@@ -70761,11 +71296,11 @@ async function updateWorkshopRegistration(id, patch) {
|
|
|
70761
71296
|
args: [...entries.map(([, value]) => value), id]
|
|
70762
71297
|
});
|
|
70763
71298
|
}
|
|
70764
|
-
var
|
|
71299
|
+
var import_node_crypto44;
|
|
70765
71300
|
var init_workshop_registration_repository = __esm({
|
|
70766
71301
|
"src/api/workshop-registration-repository.ts"() {
|
|
70767
71302
|
"use strict";
|
|
70768
|
-
|
|
71303
|
+
import_node_crypto44 = require("crypto");
|
|
70769
71304
|
init_db();
|
|
70770
71305
|
}
|
|
70771
71306
|
});
|
|
@@ -71338,7 +71873,7 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
|
71338
71873
|
articleCount: articles.length,
|
|
71339
71874
|
wordCount: totalWordCount,
|
|
71340
71875
|
bytes,
|
|
71341
|
-
sha256: (0,
|
|
71876
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex"),
|
|
71342
71877
|
warnings
|
|
71343
71878
|
};
|
|
71344
71879
|
}
|
|
@@ -71421,14 +71956,14 @@ ${provenance}`;
|
|
|
71421
71956
|
...rendered,
|
|
71422
71957
|
html,
|
|
71423
71958
|
bytes: Buffer.byteLength(html),
|
|
71424
|
-
sha256: (0,
|
|
71959
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex")
|
|
71425
71960
|
};
|
|
71426
71961
|
}
|
|
71427
|
-
var
|
|
71962
|
+
var import_node_crypto45, import_node_fs14, import_node_path21, import_marked, runtimeEntryDir, assetCache;
|
|
71428
71963
|
var init_render = __esm({
|
|
71429
71964
|
"src/editorial-reading-room/render.ts"() {
|
|
71430
71965
|
"use strict";
|
|
71431
|
-
|
|
71966
|
+
import_node_crypto45 = require("crypto");
|
|
71432
71967
|
import_node_fs14 = require("fs");
|
|
71433
71968
|
import_node_path21 = require("path");
|
|
71434
71969
|
import_marked = require("marked");
|
|
@@ -71572,8 +72107,9 @@ var init_editorial_reading_room_routes = __esm({
|
|
|
71572
72107
|
|
|
71573
72108
|
// src/api/commons-image-store.ts
|
|
71574
72109
|
async function ensureCommonsImageSchema() {
|
|
71575
|
-
|
|
71576
|
-
|
|
72110
|
+
const db = getDb();
|
|
72111
|
+
if (imageSchemaReady && imageSchemaDb === db) return;
|
|
72112
|
+
await db.execute(`
|
|
71577
72113
|
CREATE TABLE IF NOT EXISTS commons_images (
|
|
71578
72114
|
id TEXT PRIMARY KEY,
|
|
71579
72115
|
user_id INTEGER NOT NULL,
|
|
@@ -71589,8 +72125,9 @@ async function ensureCommonsImageSchema() {
|
|
|
71589
72125
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
71590
72126
|
)
|
|
71591
72127
|
`);
|
|
71592
|
-
await
|
|
72128
|
+
await db.execute(`CREATE UNIQUE INDEX IF NOT EXISTS commons_images_digest ON commons_images(digest)`);
|
|
71593
72129
|
imageSchemaReady = true;
|
|
72130
|
+
imageSchemaDb = db;
|
|
71594
72131
|
}
|
|
71595
72132
|
function sniffImageFormat(bytes) {
|
|
71596
72133
|
if (bytes.length < 12) return null;
|
|
@@ -71620,7 +72157,7 @@ async function assertPublicHttpsUrl(rawUrl) {
|
|
|
71620
72157
|
try {
|
|
71621
72158
|
url = new URL(rawUrl);
|
|
71622
72159
|
} catch {
|
|
71623
|
-
throw new CommonsImageError("image_url_invalid",
|
|
72160
|
+
throw new CommonsImageError("image_url_invalid", "The image source is not a valid URL.");
|
|
71624
72161
|
}
|
|
71625
72162
|
if (url.protocol !== "https:") {
|
|
71626
72163
|
throw new CommonsImageError("image_url_not_https", "Commons image sources must be https URLs.");
|
|
@@ -71628,7 +72165,7 @@ async function assertPublicHttpsUrl(rawUrl) {
|
|
|
71628
72165
|
const hostname = url.hostname.replace(/^\[|\]$/g, "");
|
|
71629
72166
|
const addresses = (0, import_node_net2.isIP)(hostname) ? [{ address: hostname }] : await (0, import_promises16.lookup)(hostname, { all: true }).catch(() => []);
|
|
71630
72167
|
if (!addresses.length) {
|
|
71631
|
-
throw new CommonsImageError("image_host_unresolvable",
|
|
72168
|
+
throw new CommonsImageError("image_host_unresolvable", "The image source host could not be resolved.");
|
|
71632
72169
|
}
|
|
71633
72170
|
if (addresses.some((entry) => isBlockedAddress(entry.address))) {
|
|
71634
72171
|
throw new CommonsImageError("image_host_blocked", "Commons image sources cannot resolve to private or loopback addresses.");
|
|
@@ -71639,15 +72176,36 @@ async function downloadImage(sourceUrl) {
|
|
|
71639
72176
|
let current = sourceUrl;
|
|
71640
72177
|
for (let redirect = 0; redirect <= COMMONS_IMAGE_MAX_REDIRECTS; redirect += 1) {
|
|
71641
72178
|
const url = await assertPublicHttpsUrl(current);
|
|
71642
|
-
|
|
72179
|
+
let response;
|
|
72180
|
+
try {
|
|
72181
|
+
response = await fetch(url, { redirect: "manual", signal: AbortSignal.timeout(COMMONS_IMAGE_FETCH_TIMEOUT_MS) });
|
|
72182
|
+
} catch (error) {
|
|
72183
|
+
if (error instanceof CommonsImageError) throw error;
|
|
72184
|
+
throw new CommonsImageError(
|
|
72185
|
+
"image_source_unavailable",
|
|
72186
|
+
"The image source could not be reached by Commons.",
|
|
72187
|
+
422,
|
|
72188
|
+
true
|
|
72189
|
+
);
|
|
72190
|
+
}
|
|
71643
72191
|
if (response.status >= 300 && response.status < 400) {
|
|
71644
72192
|
const location2 = response.headers.get("location");
|
|
71645
72193
|
if (!location2) throw new CommonsImageError("image_redirect_invalid", "Image source redirected without a destination.");
|
|
71646
|
-
|
|
72194
|
+
try {
|
|
72195
|
+
current = new URL(location2, url).toString();
|
|
72196
|
+
} catch {
|
|
72197
|
+
throw new CommonsImageError("image_redirect_invalid", "Image source redirected to an invalid destination.");
|
|
72198
|
+
}
|
|
71647
72199
|
continue;
|
|
71648
72200
|
}
|
|
71649
72201
|
if (!response.ok) {
|
|
71650
|
-
|
|
72202
|
+
const retryable = response.status === 408 || response.status === 425 || response.status === 429 || response.status >= 500;
|
|
72203
|
+
throw new CommonsImageError(
|
|
72204
|
+
"image_source_unavailable",
|
|
72205
|
+
`The image source returned HTTP ${response.status} and could not be hosted.`,
|
|
72206
|
+
422,
|
|
72207
|
+
retryable
|
|
72208
|
+
);
|
|
71651
72209
|
}
|
|
71652
72210
|
const declaredLength = Number(response.headers.get("content-length") ?? "0");
|
|
71653
72211
|
if (declaredLength > COMMONS_IMAGE_MAX_BYTES) {
|
|
@@ -71674,8 +72232,35 @@ function commonsImageBlobStore() {
|
|
|
71674
72232
|
const token6 = process.env.COMMONS_IMAGE_READ_WRITE_TOKEN?.trim() || process.env.COMMONS_IMAGE_BLOB_READ_WRITE_TOKEN?.trim() || process.env.BLOB_READ_WRITE_TOKEN?.trim();
|
|
71675
72233
|
return token6 ? new VercelBlobStore(token6) : getBlobStore();
|
|
71676
72234
|
}
|
|
71677
|
-
function
|
|
71678
|
-
|
|
72235
|
+
function normalizeCommonsImageUrl(rawUrl) {
|
|
72236
|
+
try {
|
|
72237
|
+
const url = new URL(rawUrl.trim());
|
|
72238
|
+
if (url.protocol !== "https:") return null;
|
|
72239
|
+
url.hash = "";
|
|
72240
|
+
return url.toString();
|
|
72241
|
+
} catch {
|
|
72242
|
+
return null;
|
|
72243
|
+
}
|
|
72244
|
+
}
|
|
72245
|
+
async function findCommonsHostedImageByUrl(rawUrl) {
|
|
72246
|
+
const url = normalizeCommonsImageUrl(rawUrl);
|
|
72247
|
+
if (!url) return null;
|
|
72248
|
+
await ensureCommonsImageSchema();
|
|
72249
|
+
const result = await getDb().execute({
|
|
72250
|
+
sql: "SELECT id, url, content_type, bytes, digest, source_url FROM commons_images WHERE url = ? LIMIT 1",
|
|
72251
|
+
args: [url]
|
|
72252
|
+
});
|
|
72253
|
+
const row = result.rows[0];
|
|
72254
|
+
if (!row) return null;
|
|
72255
|
+
return {
|
|
72256
|
+
id: String(row.id),
|
|
72257
|
+
url: String(row.url),
|
|
72258
|
+
contentType: String(row.content_type),
|
|
72259
|
+
bytes: Number(row.bytes),
|
|
72260
|
+
digest: String(row.digest),
|
|
72261
|
+
sourceUrl: row.source_url ? String(row.source_url) : null,
|
|
72262
|
+
reused: true
|
|
72263
|
+
};
|
|
71679
72264
|
}
|
|
71680
72265
|
async function hostCommonsImage(input) {
|
|
71681
72266
|
if (hostOverride) return hostOverride(input);
|
|
@@ -71692,7 +72277,7 @@ async function hostCommonsImage(input) {
|
|
|
71692
72277
|
415
|
|
71693
72278
|
);
|
|
71694
72279
|
}
|
|
71695
|
-
const digest2 = (0,
|
|
72280
|
+
const digest2 = (0, import_node_crypto46.createHash)("sha256").update(bytes).digest("hex");
|
|
71696
72281
|
const existing = await getDb().execute({
|
|
71697
72282
|
sql: "SELECT id, url, content_type, bytes, source_url FROM commons_images WHERE digest = ? LIMIT 1",
|
|
71698
72283
|
args: [digest2]
|
|
@@ -71746,7 +72331,8 @@ async function hostCommonsImage(input) {
|
|
|
71746
72331
|
async function hostEntityImages(input) {
|
|
71747
72332
|
const rewrite = { mediaUrls: /* @__PURE__ */ new Map(), dropped: [] };
|
|
71748
72333
|
const featuredUrl = input.featuredImage?.url;
|
|
71749
|
-
|
|
72334
|
+
const registeredFeatured = featuredUrl ? await findCommonsHostedImageByUrl(featuredUrl) : null;
|
|
72335
|
+
if (featuredUrl && !registeredFeatured) {
|
|
71750
72336
|
const hosted = await hostCommonsImage({
|
|
71751
72337
|
userId: input.userId,
|
|
71752
72338
|
sourceUrl: featuredUrl,
|
|
@@ -71754,17 +72340,19 @@ async function hostEntityImages(input) {
|
|
|
71754
72340
|
license: input.featuredImage?.license,
|
|
71755
72341
|
attribution: input.featuredImage?.sourceUrl
|
|
71756
72342
|
}).catch((error) => {
|
|
71757
|
-
|
|
72343
|
+
if (error instanceof CommonsImageError) throw error;
|
|
71758
72344
|
throw new CommonsImageError(
|
|
71759
|
-
|
|
71760
|
-
|
|
72345
|
+
"featured_image_unhostable",
|
|
72346
|
+
"The featured image could not be hosted, so the entity was not persisted with a link that could break.",
|
|
71761
72347
|
422
|
|
71762
72348
|
);
|
|
71763
72349
|
});
|
|
71764
72350
|
rewrite.featuredImageUrl = hosted.url;
|
|
72351
|
+
rewrite.mediaUrls.set(featuredUrl, hosted.url);
|
|
71765
72352
|
}
|
|
71766
72353
|
for (const item of input.media ?? []) {
|
|
71767
|
-
if (
|
|
72354
|
+
if (item.url && rewrite.mediaUrls.has(item.url)) continue;
|
|
72355
|
+
if (!item.url || await findCommonsHostedImageByUrl(item.url)) continue;
|
|
71768
72356
|
try {
|
|
71769
72357
|
const hosted = await hostCommonsImage({
|
|
71770
72358
|
userId: input.userId,
|
|
@@ -71780,11 +72368,11 @@ async function hostEntityImages(input) {
|
|
|
71780
72368
|
}
|
|
71781
72369
|
return rewrite;
|
|
71782
72370
|
}
|
|
71783
|
-
var
|
|
72371
|
+
var import_node_crypto46, import_promises16, import_node_net2, COMMONS_IMAGE_MAX_BYTES, COMMONS_IMAGE_MAX_REDIRECTS, COMMONS_IMAGE_FETCH_TIMEOUT_MS, COMMONS_IMAGE_RETRY_GUIDANCE, CommonsImageError, imageSchemaReady, imageSchemaDb, hostOverride;
|
|
71784
72372
|
var init_commons_image_store = __esm({
|
|
71785
72373
|
"src/api/commons-image-store.ts"() {
|
|
71786
72374
|
"use strict";
|
|
71787
|
-
|
|
72375
|
+
import_node_crypto46 = require("crypto");
|
|
71788
72376
|
import_promises16 = require("dns/promises");
|
|
71789
72377
|
import_node_net2 = require("net");
|
|
71790
72378
|
init_blob_store();
|
|
@@ -71792,17 +72380,23 @@ var init_commons_image_store = __esm({
|
|
|
71792
72380
|
COMMONS_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
71793
72381
|
COMMONS_IMAGE_MAX_REDIRECTS = 3;
|
|
71794
72382
|
COMMONS_IMAGE_FETCH_TIMEOUT_MS = 2e4;
|
|
72383
|
+
COMMONS_IMAGE_RETRY_GUIDANCE = "Call commons_host_image with a different stable public HTTPS image URL or imageBase64, replace featuredImage.url with the returned URL, validate again, then retry commons_submit_entity with the same idempotency key.";
|
|
71795
72384
|
CommonsImageError = class extends Error {
|
|
71796
|
-
constructor(code, message, httpStatus = 400) {
|
|
72385
|
+
constructor(code, message, httpStatus = 400, retryable = false, retryGuidance = COMMONS_IMAGE_RETRY_GUIDANCE) {
|
|
71797
72386
|
super(message);
|
|
71798
72387
|
this.code = code;
|
|
71799
72388
|
this.httpStatus = httpStatus;
|
|
72389
|
+
this.retryable = retryable;
|
|
72390
|
+
this.retryGuidance = retryGuidance;
|
|
71800
72391
|
this.name = "CommonsImageError";
|
|
71801
72392
|
}
|
|
71802
72393
|
code;
|
|
71803
72394
|
httpStatus;
|
|
72395
|
+
retryable;
|
|
72396
|
+
retryGuidance;
|
|
71804
72397
|
};
|
|
71805
72398
|
imageSchemaReady = false;
|
|
72399
|
+
imageSchemaDb = null;
|
|
71806
72400
|
hostOverride = null;
|
|
71807
72401
|
}
|
|
71808
72402
|
});
|
|
@@ -71909,7 +72503,7 @@ function buildCommonsLinkset(entity, claims) {
|
|
|
71909
72503
|
context[claim.predicate] = targets;
|
|
71910
72504
|
}
|
|
71911
72505
|
const document2 = { linkset: [context] };
|
|
71912
|
-
const etag = `"${(0,
|
|
72506
|
+
const etag = `"${(0, import_node_crypto47.createHash)("sha256").update(JSON.stringify(document2)).digest("hex")}"`;
|
|
71913
72507
|
return { document: document2, etag, publicUrl, linksetUrl, profile: COMMONS_RELATIONSHIP_PROFILE };
|
|
71914
72508
|
}
|
|
71915
72509
|
function commonsLinksetDiscoveryHeader(idOrSlug) {
|
|
@@ -71977,11 +72571,11 @@ function normalizeHreflang(value) {
|
|
|
71977
72571
|
const languages = [...new Set(value.map((item) => optionalText(item, 80)).filter((item) => Boolean(item)))];
|
|
71978
72572
|
return languages.length ? languages : void 0;
|
|
71979
72573
|
}
|
|
71980
|
-
var
|
|
72574
|
+
var import_node_crypto47, COMMONS_LINKSET_MEDIA_TYPE, COMMONS_RELATIONSHIP_PROFILE, REGISTERED_RELATIONS;
|
|
71981
72575
|
var init_commons_linksets = __esm({
|
|
71982
72576
|
"src/api/commons-linksets.ts"() {
|
|
71983
72577
|
"use strict";
|
|
71984
|
-
|
|
72578
|
+
import_node_crypto47 = require("crypto");
|
|
71985
72579
|
COMMONS_LINKSET_MEDIA_TYPE = "application/linkset+json";
|
|
71986
72580
|
COMMONS_RELATIONSHIP_PROFILE = "https://mcpscraper.dev/commons/profiles/relationships/v1";
|
|
71987
72581
|
REGISTERED_RELATIONS = /* @__PURE__ */ new Set([
|
|
@@ -72024,9 +72618,9 @@ var init_commons_linksets = __esm({
|
|
|
72024
72618
|
|
|
72025
72619
|
// src/api/commons-repository.ts
|
|
72026
72620
|
async function ensureCommonsSchema() {
|
|
72027
|
-
if (
|
|
72621
|
+
if (schemaReady2) return;
|
|
72028
72622
|
if (await schemaObjectsPresent(COMMONS_SCHEMA_OBJECTS)) {
|
|
72029
|
-
|
|
72623
|
+
schemaReady2 = true;
|
|
72030
72624
|
return;
|
|
72031
72625
|
}
|
|
72032
72626
|
const db = getDb();
|
|
@@ -72249,7 +72843,7 @@ async function ensureCommonsSchema() {
|
|
|
72249
72843
|
args: [COMMONS_SCHEMA_VERSION]
|
|
72250
72844
|
}
|
|
72251
72845
|
], "write");
|
|
72252
|
-
|
|
72846
|
+
schemaReady2 = true;
|
|
72253
72847
|
}
|
|
72254
72848
|
async function searchCommonsEntities(filters = {}, userId) {
|
|
72255
72849
|
await ensureCommonsSchema();
|
|
@@ -72457,7 +73051,7 @@ async function prepareCommonsEntity(input, user) {
|
|
|
72457
73051
|
normalizedEntityType: entityType,
|
|
72458
73052
|
proposedSlug: slug4 || null,
|
|
72459
73053
|
publicUrl: slug4 ? publicUrlForSlug(slug4) : null,
|
|
72460
|
-
writePath: "commons_prepare_entity -> commons_validate_entity -> commons_submit_entity"
|
|
73054
|
+
writePath: "commons_prepare_entity -> compose the entity -> commons_host_image -> commons_validate_entity -> commons_submit_entity"
|
|
72461
73055
|
},
|
|
72462
73056
|
contract,
|
|
72463
73057
|
billing: {
|
|
@@ -72479,8 +73073,8 @@ async function prepareCommonsEntity(input, user) {
|
|
|
72479
73073
|
"Search likely duplicates before submitting a new entity. If one matches, edit it with entityId and baseRevision instead of creating another page.",
|
|
72480
73074
|
"Use the returned profile as a contract, not a rigid empty template: do not include History, Reception, Pricing, Timeline, or similar sections unless source evidence supports them.",
|
|
72481
73075
|
"Write neutral encyclopedia prose. Do not paste raw scrape Markdown, marketing layout fragments, or empty/filler headings.",
|
|
72482
|
-
"
|
|
72483
|
-
"Call commons_validate_entity with the composed payload before commons_submit_entity.",
|
|
73076
|
+
"For a featured image not already hosted by Commons, call commons_host_image and replace featuredImage.url with its returned permanent URL. Preserve original URL/source byline/relCanonical when republishing, and put media assets in the media array.",
|
|
73077
|
+
"Call commons_validate_entity with the composed, image-ready payload before commons_submit_entity.",
|
|
72484
73078
|
"Validation is free. Submitting a new entity costs 10 Credits; submitting an edit to an existing entity costs 2 Credits."
|
|
72485
73079
|
]
|
|
72486
73080
|
};
|
|
@@ -72495,6 +73089,8 @@ async function validateCommonsEntity(input, user) {
|
|
|
72495
73089
|
const contract = commonsEntityProfileFor(input.entityType, input.seo?.schemaOrgType);
|
|
72496
73090
|
const source = normalizeSource(input.source);
|
|
72497
73091
|
const featuredImage = normalizeFeaturedImage(input.featuredImage);
|
|
73092
|
+
const normalizedFeaturedImageUrl = featuredImage?.url ? normalizeCommonsImageUrl(featuredImage.url) : null;
|
|
73093
|
+
const registeredFeaturedImage = normalizedFeaturedImageUrl ? await findCommonsHostedImageByUrl(normalizedFeaturedImageUrl) : null;
|
|
72498
73094
|
const bodyMarkdown = safeCandidateBody(input.bodyMarkdown, input.contentSections);
|
|
72499
73095
|
const headings = extractMarkdownHeadings(bodyMarkdown);
|
|
72500
73096
|
const placeholderSections = unsupportedPlaceholderSections(bodyMarkdown);
|
|
@@ -72532,15 +73128,44 @@ async function validateCommonsEntity(input, user) {
|
|
|
72532
73128
|
if (input.reviewPolicy === "always_review") {
|
|
72533
73129
|
warnings.push("reviewPolicy is always_review, so the proposal will not auto-publish even if the payload is otherwise valid.");
|
|
72534
73130
|
}
|
|
73131
|
+
if (featuredImage?.url && !registeredFeaturedImage) {
|
|
73132
|
+
warnings.push("The featured image is not registered in permanent Commons image storage. Call commons_host_image, replace featuredImage.url with its returned URL, and validate again before submitting.");
|
|
73133
|
+
}
|
|
72535
73134
|
if (user?.id == null) warnings.push("No authenticated user was supplied to validation; submit still requires API-key authenticated user context.");
|
|
72536
73135
|
const valid = errors.length === 0;
|
|
72537
|
-
const
|
|
73136
|
+
const imageReadyForPublish = Boolean(registeredFeaturedImage);
|
|
73137
|
+
const publishable = valid && imageReadyForPublish;
|
|
73138
|
+
const autoPublishEligible = publishable && input.reviewPolicy !== "always_review";
|
|
72538
73139
|
const tagVocabulary = await commonsTagVocabulary();
|
|
72539
73140
|
return {
|
|
72540
73141
|
ok: true,
|
|
72541
73142
|
valid,
|
|
72542
|
-
publishable
|
|
73143
|
+
publishable,
|
|
72543
73144
|
autoPublishEligible,
|
|
73145
|
+
imageDiagnostics: {
|
|
73146
|
+
featuredImage: registeredFeaturedImage ? {
|
|
73147
|
+
state: "commons_hosted",
|
|
73148
|
+
url: registeredFeaturedImage.url,
|
|
73149
|
+
commonsImageId: registeredFeaturedImage.id,
|
|
73150
|
+
readyForPublish: true,
|
|
73151
|
+
submitWillAttemptAutoHost: false,
|
|
73152
|
+
requiredAction: null
|
|
73153
|
+
} : featuredImage?.url ? {
|
|
73154
|
+
state: "external_unhosted",
|
|
73155
|
+
url: normalizedFeaturedImageUrl,
|
|
73156
|
+
commonsImageId: null,
|
|
73157
|
+
readyForPublish: false,
|
|
73158
|
+
submitWillAttemptAutoHost: true,
|
|
73159
|
+
requiredAction: "Call commons_host_image, replace featuredImage.url with its returned permanent URL, and validate again."
|
|
73160
|
+
} : {
|
|
73161
|
+
state: "missing",
|
|
73162
|
+
url: null,
|
|
73163
|
+
commonsImageId: null,
|
|
73164
|
+
readyForPublish: false,
|
|
73165
|
+
submitWillAttemptAutoHost: false,
|
|
73166
|
+
requiredAction: "Add a featured image by calling commons_host_image, then set featuredImage.url to its returned permanent URL."
|
|
73167
|
+
}
|
|
73168
|
+
},
|
|
72544
73169
|
errors,
|
|
72545
73170
|
warnings,
|
|
72546
73171
|
contract,
|
|
@@ -72621,7 +73246,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
72621
73246
|
const existingClaims = existing && normalized.claims !== void 0 ? await getCommonsClaimsByEntityId(existing.id) : [];
|
|
72622
73247
|
const safety = evaluatePublishSafety(normalized, existing);
|
|
72623
73248
|
const shouldApply = safety.safe && normalized.reviewPolicy !== "always_review";
|
|
72624
|
-
const proposalId = `commons-proposal-${(0,
|
|
73249
|
+
const proposalId = `commons-proposal-${(0, import_node_crypto48.randomUUID)()}`;
|
|
72625
73250
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
72626
73251
|
const entityId = existing?.id ?? normalized.entityId ?? allocateEntityId();
|
|
72627
73252
|
const proposalStatus = shouldApply ? "accepted" : "pending_review";
|
|
@@ -72676,7 +73301,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
72676
73301
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
72677
73302
|
`,
|
|
72678
73303
|
args: [
|
|
72679
|
-
`commons-ledger-${(0,
|
|
73304
|
+
`commons-ledger-${(0, import_node_crypto48.randomUUID)()}`,
|
|
72680
73305
|
nextEntity.id,
|
|
72681
73306
|
proposalId,
|
|
72682
73307
|
user.id,
|
|
@@ -72782,7 +73407,7 @@ async function saveCommonsFilter(input, user) {
|
|
|
72782
73407
|
sql: "SELECT id FROM commons_saved_filters WHERE user_id = ? AND name = ? LIMIT 1",
|
|
72783
73408
|
args: [user.id, name]
|
|
72784
73409
|
});
|
|
72785
|
-
const id = existing.rows[0]?.id != null ? String(existing.rows[0].id) : `commons-filter-${(0,
|
|
73410
|
+
const id = existing.rows[0]?.id != null ? String(existing.rows[0].id) : `commons-filter-${(0, import_node_crypto48.randomUUID)()}`;
|
|
72786
73411
|
await getDb().execute({
|
|
72787
73412
|
sql: `
|
|
72788
73413
|
INSERT INTO commons_saved_filters (id, user_id, name, description, filter_json, created_at, updated_at)
|
|
@@ -73560,7 +74185,7 @@ function commonsIndexDocuments(entity, now) {
|
|
|
73560
74185
|
return documents;
|
|
73561
74186
|
}
|
|
73562
74187
|
function commonsIndexDocumentId(entityId, documentType, documentKey) {
|
|
73563
|
-
return `commons-index-${(0,
|
|
74188
|
+
return `commons-index-${(0, import_node_crypto48.createHash)("sha256").update(`${entityId}
|
|
73564
74189
|
${documentType}
|
|
73565
74190
|
${documentKey}`).digest("hex").slice(0, 32)}`;
|
|
73566
74191
|
}
|
|
@@ -74126,11 +74751,11 @@ function jsonLikeValue(value) {
|
|
|
74126
74751
|
function escapeLike(value) {
|
|
74127
74752
|
return value.replace(/[%_]/g, "");
|
|
74128
74753
|
}
|
|
74129
|
-
var
|
|
74754
|
+
var import_node_crypto48, COMMONS_SCHEMA_VERSION, DEFAULT_COMMONS_BASE_URL, DEFAULT_ENTITY_TYPE, COMMONS_ENTITY_PROFILES, schemaReady2, COMMONS_SCHEMA_OBJECTS, SEARCH_CANDIDATE_LIMIT, CommonsRepositoryError;
|
|
74130
74755
|
var init_commons_repository = __esm({
|
|
74131
74756
|
"src/api/commons-repository.ts"() {
|
|
74132
74757
|
"use strict";
|
|
74133
|
-
|
|
74758
|
+
import_node_crypto48 = require("crypto");
|
|
74134
74759
|
init_db();
|
|
74135
74760
|
init_commons_image_store();
|
|
74136
74761
|
init_commons_embeddings();
|
|
@@ -74285,7 +74910,7 @@ var init_commons_repository = __esm({
|
|
|
74285
74910
|
]
|
|
74286
74911
|
}
|
|
74287
74912
|
};
|
|
74288
|
-
|
|
74913
|
+
schemaReady2 = false;
|
|
74289
74914
|
COMMONS_SCHEMA_OBJECTS = [
|
|
74290
74915
|
"schema_migrations",
|
|
74291
74916
|
"commons_entities",
|
|
@@ -74509,7 +75134,7 @@ async function claimCommonsPublication(input, user) {
|
|
|
74509
75134
|
}
|
|
74510
75135
|
const existingName = await getCommonsPublicationBySubdomain(subdomain);
|
|
74511
75136
|
if (existingName) throw new CommonsPublicationError("publication_name_unavailable", "That publication name is already claimed.", 409);
|
|
74512
|
-
const id = `tcpub_${(0,
|
|
75137
|
+
const id = `tcpub_${(0, import_node_crypto49.randomUUID)()}`;
|
|
74513
75138
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
74514
75139
|
try {
|
|
74515
75140
|
await getDb().execute({
|
|
@@ -74561,7 +75186,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
74561
75186
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
74562
75187
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
74563
75188
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
74564
|
-
const editionId = `tced_${(0,
|
|
75189
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
74565
75190
|
const revision = (latest?.revision ?? 0) + 1;
|
|
74566
75191
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
74567
75192
|
await getDb().batch([
|
|
@@ -74585,7 +75210,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
74585
75210
|
JSON.stringify(editionInput.articles),
|
|
74586
75211
|
html,
|
|
74587
75212
|
rendered.filename,
|
|
74588
|
-
(0,
|
|
75213
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
74589
75214
|
rendered.articleCount,
|
|
74590
75215
|
rendered.wordCount,
|
|
74591
75216
|
Buffer.byteLength(html),
|
|
@@ -74643,7 +75268,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
74643
75268
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
74644
75269
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
74645
75270
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
74646
|
-
const editionId = `tced_${(0,
|
|
75271
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
74647
75272
|
const revision = latest.revision + 1;
|
|
74648
75273
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
74649
75274
|
await getDb().batch([
|
|
@@ -74667,7 +75292,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
74667
75292
|
JSON.stringify(nextArticles),
|
|
74668
75293
|
html,
|
|
74669
75294
|
rendered.filename,
|
|
74670
|
-
(0,
|
|
75295
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
74671
75296
|
rendered.articleCount,
|
|
74672
75297
|
rendered.wordCount,
|
|
74673
75298
|
Buffer.byteLength(html),
|
|
@@ -74872,11 +75497,11 @@ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
|
|
|
74872
75497
|
"</head>"
|
|
74873
75498
|
].join("\n"));
|
|
74874
75499
|
}
|
|
74875
|
-
var
|
|
75500
|
+
var import_node_crypto49, PUBLICATION_ROOT_DOMAIN, RESERVED_SUBDOMAINS, CommonsPublicationError;
|
|
74876
75501
|
var init_commons_publication_repository = __esm({
|
|
74877
75502
|
"src/api/commons-publication-repository.ts"() {
|
|
74878
75503
|
"use strict";
|
|
74879
|
-
|
|
75504
|
+
import_node_crypto49 = require("crypto");
|
|
74880
75505
|
init_db();
|
|
74881
75506
|
init_commons_repository();
|
|
74882
75507
|
init_render();
|
|
@@ -74963,6 +75588,18 @@ function repositoryStatus(error) {
|
|
|
74963
75588
|
if (error.httpStatus === 409) return 409;
|
|
74964
75589
|
return 400;
|
|
74965
75590
|
}
|
|
75591
|
+
function imageErrorResponse(c, error, chargeStatus) {
|
|
75592
|
+
return c.json({
|
|
75593
|
+
ok: false,
|
|
75594
|
+
error: error.code,
|
|
75595
|
+
error_code: error.code,
|
|
75596
|
+
error_type: "invalid_request",
|
|
75597
|
+
retryable: error.retryable,
|
|
75598
|
+
...chargeStatus ? { charge_status: chargeStatus } : {},
|
|
75599
|
+
message: `${error.message} ${error.retryGuidance}`,
|
|
75600
|
+
details: { retry_guidance: error.retryGuidance }
|
|
75601
|
+
}, error.httpStatus);
|
|
75602
|
+
}
|
|
74966
75603
|
async function publicationOperation(c, operation, successStatus = 200) {
|
|
74967
75604
|
try {
|
|
74968
75605
|
return c.json({ ok: true, data: await operation() }, successStatus);
|
|
@@ -75303,7 +75940,7 @@ var init_commons_routes = __esm({
|
|
|
75303
75940
|
return c.json({ ok: true, data: hosted }, hosted.reused ? 200 : 201);
|
|
75304
75941
|
} catch (error) {
|
|
75305
75942
|
if (error instanceof CommonsImageError) {
|
|
75306
|
-
return c
|
|
75943
|
+
return imageErrorResponse(c, error);
|
|
75307
75944
|
}
|
|
75308
75945
|
throw error;
|
|
75309
75946
|
}
|
|
@@ -75367,7 +76004,14 @@ var init_commons_routes = __esm({
|
|
|
75367
76004
|
}
|
|
75368
76005
|
return c.json({ ok: true, data: result, billing: publicListingWriteBilling(billing) }, 201);
|
|
75369
76006
|
} catch (error) {
|
|
75370
|
-
|
|
76007
|
+
let chargeStatus = billing ? billing.duplicate ? "not_charged" : "refund_pending" : "not_charged";
|
|
76008
|
+
if (billing && !billing.duplicate) {
|
|
76009
|
+
const settlement = await refundListingWrite(billing, "Transparent Commons write failed before persistence.").catch(() => null);
|
|
76010
|
+
if (settlement) chargeStatus = "refunded";
|
|
76011
|
+
}
|
|
76012
|
+
if (error instanceof CommonsImageError) {
|
|
76013
|
+
return imageErrorResponse(c, error, chargeStatus);
|
|
76014
|
+
}
|
|
75371
76015
|
if (error instanceof CommonsRepositoryError) {
|
|
75372
76016
|
return c.json({ ok: false, error: error.code, message: error.message }, repositoryStatus(error));
|
|
75373
76017
|
}
|
|
@@ -76109,7 +76753,7 @@ async function migrateAnalytics() {
|
|
|
76109
76753
|
}
|
|
76110
76754
|
function normalizeSlug2(value) {
|
|
76111
76755
|
const slug4 = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
76112
|
-
return slug4 || `site-${(0,
|
|
76756
|
+
return slug4 || `site-${(0, import_node_crypto50.randomBytes)(4).toString("hex")}`;
|
|
76113
76757
|
}
|
|
76114
76758
|
function normalizeObservedHostname(origin) {
|
|
76115
76759
|
if (!origin || origin === "null") return null;
|
|
@@ -76122,7 +76766,7 @@ function normalizeObservedHostname(origin) {
|
|
|
76122
76766
|
}
|
|
76123
76767
|
}
|
|
76124
76768
|
function publicPixelId() {
|
|
76125
|
-
return `px_${(0,
|
|
76769
|
+
return `px_${(0, import_node_crypto50.randomBytes)(18).toString("base64url")}`;
|
|
76126
76770
|
}
|
|
76127
76771
|
function mapRows(rows) {
|
|
76128
76772
|
return rows;
|
|
@@ -76154,7 +76798,7 @@ async function requireEditor(client2, siteId, userId) {
|
|
|
76154
76798
|
async function createAnalyticsSite(input) {
|
|
76155
76799
|
const db = getAnalyticsPool();
|
|
76156
76800
|
const client2 = await db.connect();
|
|
76157
|
-
const id = (0,
|
|
76801
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76158
76802
|
const baseSlug = normalizeSlug2(input.slug || input.name);
|
|
76159
76803
|
try {
|
|
76160
76804
|
await client2.query("BEGIN");
|
|
@@ -76170,7 +76814,7 @@ async function createAnalyticsSite(input) {
|
|
|
76170
76814
|
} catch (error) {
|
|
76171
76815
|
const code = error.code;
|
|
76172
76816
|
if (code !== "23505" || attempt === 2) throw error;
|
|
76173
|
-
slug4 = `${baseSlug}-${(0,
|
|
76817
|
+
slug4 = `${baseSlug}-${(0, import_node_crypto50.randomBytes)(2).toString("hex")}`;
|
|
76174
76818
|
}
|
|
76175
76819
|
}
|
|
76176
76820
|
await client2.query(
|
|
@@ -76385,7 +77029,7 @@ async function createAnalyticsPixel(input) {
|
|
|
76385
77029
|
VALUES ($1, $2, $3, $4, $5)
|
|
76386
77030
|
RETURNING id, site_id, public_id, name, environment, status, created_at::text, NULL::text AS last_event_at`,
|
|
76387
77031
|
[
|
|
76388
|
-
(0,
|
|
77032
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76389
77033
|
input.siteId,
|
|
76390
77034
|
publicPixelId(),
|
|
76391
77035
|
input.name.trim(),
|
|
@@ -76462,7 +77106,7 @@ async function setAnalyticsPixelDomainState(input) {
|
|
|
76462
77106
|
SELECT $1, p.id, $4, $5 FROM analytics_pixels p WHERE p.id = $2 AND p.site_id = $3
|
|
76463
77107
|
ON CONFLICT(pixel_id, hostname) DO UPDATE SET state = EXCLUDED.state, updated_at = now()
|
|
76464
77108
|
RETURNING id`,
|
|
76465
|
-
[(0,
|
|
77109
|
+
[(0, import_node_crypto50.randomUUID)(), input.pixelId, input.siteId, hostname, input.state]
|
|
76466
77110
|
);
|
|
76467
77111
|
if (!result.rowCount)
|
|
76468
77112
|
throw new AnalyticsRepositoryError(
|
|
@@ -76512,7 +77156,7 @@ function sanitizeAnalyticsProperties(value) {
|
|
|
76512
77156
|
}
|
|
76513
77157
|
async function ingestAnalyticsEvents(input) {
|
|
76514
77158
|
const db = getAnalyticsPool();
|
|
76515
|
-
const requestId = `air_${(0,
|
|
77159
|
+
const requestId = `air_${(0, import_node_crypto50.randomUUID)()}`;
|
|
76516
77160
|
const hostname = normalizeObservedHostname(input.origin);
|
|
76517
77161
|
const pixelResult = await db.query(
|
|
76518
77162
|
`SELECT p.id, p.site_id, p.status,
|
|
@@ -76533,7 +77177,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76533
77177
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
76534
77178
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
76535
77179
|
[
|
|
76536
|
-
(0,
|
|
77180
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76537
77181
|
requestId,
|
|
76538
77182
|
pixel?.site_id ?? null,
|
|
76539
77183
|
pixel?.id ?? null,
|
|
@@ -76558,7 +77202,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76558
77202
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
76559
77203
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
76560
77204
|
[
|
|
76561
|
-
(0,
|
|
77205
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76562
77206
|
requestId,
|
|
76563
77207
|
pixel.site_id,
|
|
76564
77208
|
pixel.id,
|
|
@@ -76583,7 +77227,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76583
77227
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, rejected_count, reason_codes)
|
|
76584
77228
|
VALUES ($1, $2, $3, $4, $5, $6::jsonb)`,
|
|
76585
77229
|
[
|
|
76586
|
-
(0,
|
|
77230
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76587
77231
|
requestId,
|
|
76588
77232
|
pixel.site_id,
|
|
76589
77233
|
pixel.id,
|
|
@@ -76607,7 +77251,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76607
77251
|
ON CONFLICT(pixel_id, hostname) DO UPDATE
|
|
76608
77252
|
SET last_seen_at = now(), updated_at = now()
|
|
76609
77253
|
RETURNING state`,
|
|
76610
|
-
[(0,
|
|
77254
|
+
[(0, import_node_crypto50.randomUUID)(), pixel.id, hostname]
|
|
76611
77255
|
);
|
|
76612
77256
|
if (domainResult.rows[0]?.state !== "approved") {
|
|
76613
77257
|
await db.query(
|
|
@@ -76621,7 +77265,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76621
77265
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
76622
77266
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
76623
77267
|
[
|
|
76624
|
-
(0,
|
|
77268
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76625
77269
|
requestId,
|
|
76626
77270
|
pixel.site_id,
|
|
76627
77271
|
pixel.id,
|
|
@@ -76671,7 +77315,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76671
77315
|
$23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33
|
|
76672
77316
|
) ON CONFLICT(site_id, event_id) DO NOTHING`,
|
|
76673
77317
|
[
|
|
76674
|
-
(0,
|
|
77318
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76675
77319
|
event2.eventId,
|
|
76676
77320
|
pixel.site_id,
|
|
76677
77321
|
pixel.id,
|
|
@@ -76729,7 +77373,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76729
77373
|
id, request_id, site_id, pixel_id, hostname, accepted_count, rejected_count, reason_codes
|
|
76730
77374
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb)`,
|
|
76731
77375
|
[
|
|
76732
|
-
(0,
|
|
77376
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76733
77377
|
requestId,
|
|
76734
77378
|
pixel.site_id,
|
|
76735
77379
|
pixel.id,
|
|
@@ -76761,7 +77405,7 @@ function normalizeGeographyCode(value, max) {
|
|
|
76761
77405
|
return normalized && /^[A-Z0-9-]+$/.test(normalized) ? normalized.slice(0, max) : null;
|
|
76762
77406
|
}
|
|
76763
77407
|
function pageFingerprint(scope, siteId, filters) {
|
|
76764
|
-
return (0,
|
|
77408
|
+
return (0, import_node_crypto50.createHash)("sha256").update(JSON.stringify({ scope, siteId, filters })).digest("base64url").slice(0, 18);
|
|
76765
77409
|
}
|
|
76766
77410
|
function decodePageOffset(cursor, fingerprint2) {
|
|
76767
77411
|
if (!cursor) return 0;
|
|
@@ -76811,7 +77455,7 @@ async function createAnalyticsConversion(input) {
|
|
|
76811
77455
|
404
|
|
76812
77456
|
);
|
|
76813
77457
|
}
|
|
76814
|
-
const id = (0,
|
|
77458
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76815
77459
|
const resolvedPerson = input.sessionId ? await db.query(
|
|
76816
77460
|
`SELECT e.person_id FROM analytics_identity_nodes n JOIN analytics_identity_edges e ON e.identity_node_id = n.id
|
|
76817
77461
|
WHERE n.site_id = $1 AND n.kind = 'session_id' AND n.value_hmac = $2 ORDER BY e.confidence DESC LIMIT 1`,
|
|
@@ -77560,7 +78204,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
77560
78204
|
404
|
|
77561
78205
|
);
|
|
77562
78206
|
}
|
|
77563
|
-
const shortCode = (input.shortCode?.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-") || (0,
|
|
78207
|
+
const shortCode = (input.shortCode?.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "-") || (0, import_node_crypto50.randomBytes)(5).toString("base64url").toLowerCase()).slice(0, 48);
|
|
77564
78208
|
try {
|
|
77565
78209
|
const result = await db.query(
|
|
77566
78210
|
`INSERT INTO analytics_campaign_links(
|
|
@@ -77569,7 +78213,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
77569
78213
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
|
|
77570
78214
|
RETURNING *, 0::int AS click_count`,
|
|
77571
78215
|
[
|
|
77572
|
-
(0,
|
|
78216
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77573
78217
|
input.siteId,
|
|
77574
78218
|
input.pixelId ?? null,
|
|
77575
78219
|
input.name.trim(),
|
|
@@ -77640,7 +78284,7 @@ async function resolveAnalyticsCampaignLink(shortCode, referrer) {
|
|
|
77640
78284
|
if (!row) return null;
|
|
77641
78285
|
await db.query(
|
|
77642
78286
|
`INSERT INTO analytics_campaign_clicks(id, link_id, referrer) VALUES ($1, $2, $3)`,
|
|
77643
|
-
[(0,
|
|
78287
|
+
[(0, import_node_crypto50.randomUUID)(), row.id, normalizeAnalyticsUrl(referrer || void 0)]
|
|
77644
78288
|
);
|
|
77645
78289
|
return buildTaggedCampaignUrl(row);
|
|
77646
78290
|
}
|
|
@@ -77658,14 +78302,14 @@ async function createAnalyticsForm(input) {
|
|
|
77658
78302
|
404
|
|
77659
78303
|
);
|
|
77660
78304
|
const baseSlug = normalizeSlug2(input.name);
|
|
77661
|
-
const slug4 = `${baseSlug}-${(0,
|
|
77662
|
-
const publicId = `form_${(0,
|
|
78305
|
+
const slug4 = `${baseSlug}-${(0, import_node_crypto50.randomBytes)(3).toString("hex")}`;
|
|
78306
|
+
const publicId = `form_${(0, import_node_crypto50.randomBytes)(18).toString("base64url")}`;
|
|
77663
78307
|
const result = await db.query(
|
|
77664
78308
|
`INSERT INTO analytics_forms(id, public_id, site_id, pixel_id, name, slug, fields, brand, submit_label, success_message, redirect_url, consent_text, status, created_by_user_id)
|
|
77665
78309
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb,$9,$10,$11,$12,$13,$14)
|
|
77666
78310
|
RETURNING *, 0::int AS submission_count`,
|
|
77667
78311
|
[
|
|
77668
|
-
(0,
|
|
78312
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77669
78313
|
publicId,
|
|
77670
78314
|
input.siteId,
|
|
77671
78315
|
input.pixelId,
|
|
@@ -77710,7 +78354,7 @@ async function getPublicAnalyticsForm(publicId) {
|
|
|
77710
78354
|
return result.rows[0] ?? null;
|
|
77711
78355
|
}
|
|
77712
78356
|
async function recordAnalyticsFormSubmission(input) {
|
|
77713
|
-
const id = (0,
|
|
78357
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
77714
78358
|
await getAnalyticsPool().query(
|
|
77715
78359
|
`INSERT INTO analytics_form_submissions(id, form_id, site_id, pixel_id, visitor_id, session_id, crm_person_ref, source, medium, campaign, crm_delivery_status, click_ids)
|
|
77716
78360
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb)`,
|
|
@@ -77741,7 +78385,7 @@ function sanitizeClickIds(value) {
|
|
|
77741
78385
|
return output;
|
|
77742
78386
|
}
|
|
77743
78387
|
function identityHmac(kind, value) {
|
|
77744
|
-
return (0,
|
|
78388
|
+
return (0, import_node_crypto50.createHmac)("sha256", getSessionSecret()).update(`${kind}:${value.trim().toLowerCase()}`).digest("hex");
|
|
77745
78389
|
}
|
|
77746
78390
|
async function linkAnalyticsFormIdentity(input) {
|
|
77747
78391
|
const client2 = await getAnalyticsPool().connect();
|
|
@@ -77750,7 +78394,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
77750
78394
|
const person = await client2.query(
|
|
77751
78395
|
`INSERT INTO analytics_people(id, site_id, crm_person_ref) VALUES ($1,$2,$3)
|
|
77752
78396
|
ON CONFLICT(site_id, crm_person_ref) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
77753
|
-
[(0,
|
|
78397
|
+
[(0, import_node_crypto50.randomUUID)(), input.siteId, input.crmPersonRef]
|
|
77754
78398
|
);
|
|
77755
78399
|
const personId = person.rows[0].id;
|
|
77756
78400
|
const signals = [];
|
|
@@ -77797,7 +78441,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
77797
78441
|
`INSERT INTO analytics_identity_nodes(id, site_id, kind, value_hmac) VALUES ($1,$2,$3,$4)
|
|
77798
78442
|
ON CONFLICT(site_id, kind, value_hmac) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
77799
78443
|
[
|
|
77800
|
-
(0,
|
|
78444
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77801
78445
|
input.siteId,
|
|
77802
78446
|
signal.kind,
|
|
77803
78447
|
identityHmac(signal.kind, signal.value)
|
|
@@ -77808,7 +78452,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
77808
78452
|
VALUES ($1,$2,$3,$4,$5,$6)
|
|
77809
78453
|
ON CONFLICT(person_id, identity_node_id, evidence_kind) DO UPDATE SET last_seen_at = now(), confidence = greatest(analytics_identity_edges.confidence, EXCLUDED.confidence)`,
|
|
77810
78454
|
[
|
|
77811
|
-
(0,
|
|
78455
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77812
78456
|
input.siteId,
|
|
77813
78457
|
personId,
|
|
77814
78458
|
node.rows[0].id,
|
|
@@ -77906,7 +78550,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
77906
78550
|
const db = getAnalyticsPool();
|
|
77907
78551
|
await requireEditor(db, input.siteId, input.userId);
|
|
77908
78552
|
const client2 = await db.connect();
|
|
77909
|
-
const id = (0,
|
|
78553
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
77910
78554
|
try {
|
|
77911
78555
|
await client2.query("BEGIN");
|
|
77912
78556
|
await client2.query(
|
|
@@ -77926,7 +78570,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
77926
78570
|
await client2.query(
|
|
77927
78571
|
`INSERT INTO analytics_crm_import_rows(id, import_id, crm_person_ref, payload_ciphertext)
|
|
77928
78572
|
VALUES ($1,$2,$3,$4) ON CONFLICT(import_id, crm_person_ref) DO NOTHING`,
|
|
77929
|
-
[(0,
|
|
78573
|
+
[(0, import_node_crypto50.randomUUID)(), id, row.crmPersonRef, row.payloadCiphertext]
|
|
77930
78574
|
);
|
|
77931
78575
|
}
|
|
77932
78576
|
await client2.query("COMMIT");
|
|
@@ -77965,7 +78609,7 @@ async function createAnalyticsActivationDestination(input) {
|
|
|
77965
78609
|
`INSERT INTO analytics_activation_destinations(id, site_id, platform, name, connection_ref, external_dataset_id, event_mapping, created_by_user_id)
|
|
77966
78610
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8) RETURNING *`,
|
|
77967
78611
|
[
|
|
77968
|
-
(0,
|
|
78612
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77969
78613
|
input.siteId,
|
|
77970
78614
|
input.platform,
|
|
77971
78615
|
input.name.trim(),
|
|
@@ -78017,7 +78661,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
78017
78661
|
`INSERT INTO analytics_activation_jobs(id, destination_id, conversion_id, person_id, payload_ciphertext)
|
|
78018
78662
|
VALUES ($1,$2,$3,$4,$5) ON CONFLICT(destination_id, conversion_id) DO NOTHING`,
|
|
78019
78663
|
[
|
|
78020
|
-
(0,
|
|
78664
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
78021
78665
|
destination.id,
|
|
78022
78666
|
input.conversionId,
|
|
78023
78667
|
input.personId ?? null,
|
|
@@ -78029,7 +78673,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
78029
78673
|
return queued;
|
|
78030
78674
|
}
|
|
78031
78675
|
async function queueAnalyticsFormDelivery(input) {
|
|
78032
|
-
const id = (0,
|
|
78676
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
78033
78677
|
await getAnalyticsPool().query(
|
|
78034
78678
|
`INSERT INTO analytics_form_delivery_jobs(id, submission_id, owner_user_id, payload_ciphertext, last_error_code)
|
|
78035
78679
|
VALUES ($1,$2,$3,$4,$5)`,
|
|
@@ -78156,7 +78800,7 @@ async function analyticsHealth(siteId, userId) {
|
|
|
78156
78800
|
}
|
|
78157
78801
|
async function refreshAnalyticsDailyRollups(input) {
|
|
78158
78802
|
const db = getAnalyticsPool();
|
|
78159
|
-
const runId = (0,
|
|
78803
|
+
const runId = (0, import_node_crypto50.randomUUID)();
|
|
78160
78804
|
await db.query(
|
|
78161
78805
|
`INSERT INTO analytics_rollup_runs(id, window_start, window_end, status) VALUES ($1, $2, $3, 'running')`,
|
|
78162
78806
|
[runId, input.start, input.end]
|
|
@@ -78353,7 +78997,7 @@ async function createAnalyticsExport(input) {
|
|
|
78353
78997
|
`Generated ${(/* @__PURE__ */ new Date()).toISOString()} from the governed ${input.report} report contract.`
|
|
78354
78998
|
].join("\n");
|
|
78355
78999
|
}
|
|
78356
|
-
const id = (0,
|
|
79000
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
78357
79001
|
const inserted = await getAnalyticsPool().query(
|
|
78358
79002
|
`INSERT INTO analytics_exports(id, site_id, requested_by_user_id, idempotency_key, report, format, filters, content)
|
|
78359
79003
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8)
|
|
@@ -78386,11 +79030,11 @@ async function createAnalyticsExport(input) {
|
|
|
78386
79030
|
}
|
|
78387
79031
|
return describeArtifact(replay.rows[0]);
|
|
78388
79032
|
}
|
|
78389
|
-
var
|
|
79033
|
+
var import_node_crypto50, import_pg, AnalyticsRepositoryError, pool2, MAX_ENGAGED_MS, ENGAGED_SESSION_MS, blockedPropertyName, inferredFamilySql, ANALYTICS_CONTENT_SORTS, clickIdKeys;
|
|
78390
79034
|
var init_analytics_repository = __esm({
|
|
78391
79035
|
"src/api/analytics-repository.ts"() {
|
|
78392
79036
|
"use strict";
|
|
78393
|
-
|
|
79037
|
+
import_node_crypto50 = require("crypto");
|
|
78394
79038
|
import_pg = require("pg");
|
|
78395
79039
|
init_session();
|
|
78396
79040
|
init_analytics_attribution();
|
|
@@ -78629,8 +79273,8 @@ function dashboardCallbackUrl() {
|
|
|
78629
79273
|
}
|
|
78630
79274
|
async function createThorbitConnectUrl(userId) {
|
|
78631
79275
|
if (!bridgeConfigured()) throw new Error("Thorbit X-Ray account bridge is not configured");
|
|
78632
|
-
const state = (0,
|
|
78633
|
-
const stateHash = (0,
|
|
79276
|
+
const state = (0, import_node_crypto51.randomBytes)(32).toString("base64url");
|
|
79277
|
+
const stateHash = (0, import_node_crypto51.createHash)("sha256").update(state).digest("hex");
|
|
78634
79278
|
await getAnalyticsPool().query(
|
|
78635
79279
|
`INSERT INTO analytics_thorbit_connect_states(state_hash,user_id,expires_at)
|
|
78636
79280
|
VALUES ($1,$2,now()+interval '10 minutes')
|
|
@@ -78645,9 +79289,9 @@ async function createThorbitConnectUrl(userId) {
|
|
|
78645
79289
|
function verifyThorbitAssertion(token6) {
|
|
78646
79290
|
const [encoded, signature] = token6.split(".");
|
|
78647
79291
|
if (!encoded || !signature || !bridgeConfigured()) throw new Error("Invalid Thorbit assertion");
|
|
78648
|
-
const expected = (0,
|
|
79292
|
+
const expected = (0, import_node_crypto51.createHmac)("sha256", bridgeSecret()).update(encoded).digest();
|
|
78649
79293
|
const actual = Buffer.from(signature, "base64url");
|
|
78650
|
-
if (actual.length !== expected.length || !(0,
|
|
79294
|
+
if (actual.length !== expected.length || !(0, import_node_crypto51.timingSafeEqual)(actual, expected)) {
|
|
78651
79295
|
throw new Error("Invalid Thorbit assertion signature");
|
|
78652
79296
|
}
|
|
78653
79297
|
const parsed = AssertionSchema.safeParse(
|
|
@@ -78659,7 +79303,7 @@ function verifyThorbitAssertion(token6) {
|
|
|
78659
79303
|
return parsed.data.entitlement;
|
|
78660
79304
|
}
|
|
78661
79305
|
async function consumeThorbitConnectCallback(input) {
|
|
78662
|
-
const stateHash = (0,
|
|
79306
|
+
const stateHash = (0, import_node_crypto51.createHash)("sha256").update(input.state).digest("hex");
|
|
78663
79307
|
const client2 = await getAnalyticsPool().connect();
|
|
78664
79308
|
try {
|
|
78665
79309
|
await client2.query("BEGIN");
|
|
@@ -78699,11 +79343,11 @@ async function disconnectAnalyticsEntitlement(userId) {
|
|
|
78699
79343
|
[userId]
|
|
78700
79344
|
);
|
|
78701
79345
|
}
|
|
78702
|
-
var
|
|
79346
|
+
var import_node_crypto51, import_zod55, THORBIT_PRODUCT_URL, REFRESH_INTERVAL_MS, ELIGIBLE_GRACE_MS, TRIAL_LENGTH_MS, ThorbitEntitlementSchema, AssertionSchema;
|
|
78703
79347
|
var init_analytics_entitlement = __esm({
|
|
78704
79348
|
"src/api/analytics-entitlement.ts"() {
|
|
78705
79349
|
"use strict";
|
|
78706
|
-
|
|
79350
|
+
import_node_crypto51 = require("crypto");
|
|
78707
79351
|
import_zod55 = require("zod");
|
|
78708
79352
|
init_analytics_repository();
|
|
78709
79353
|
THORBIT_PRODUCT_URL = "https://thorbit.ai";
|
|
@@ -78843,14 +79487,14 @@ function renderPublicForm(form, placementUrl) {
|
|
|
78843
79487
|
const brand = form.brand;
|
|
78844
79488
|
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{font-family:ui-sans-serif,system-ui;color:${escapeHtml8(brand.textColor)};background:${escapeHtml8(brand.backgroundColor)}}*{box-sizing:border-box}body{margin:0;padding:18px}form{display:grid;gap:14px}label{display:grid;gap:6px;font-size:13px;font-weight:650}.check{grid-template-columns:auto 1fr;align-items:center}.check span{grid-column:2}.check input{grid-column:1;grid-row:1}input,textarea,select{width:100%;min-height:44px;padding:10px 12px;border:1px solid #ccd3df;border-radius:${brand.radius}px;background:white;color:inherit;font:inherit}textarea{min-height:110px;resize:vertical}button{min-height:46px;border:0;border-radius:${brand.radius}px;color:white;background:${escapeHtml8(brand.primaryColor)};font:inherit;font-weight:750;cursor:pointer}.consent{margin:0;color:#667085;font-size:11px;line-height:1.45}.notice{display:none;padding:12px;border-radius:${brand.radius}px;background:#edf8f2;color:#17613c}.hp{position:absolute!important;left:-9999px!important}</style></head><body><form id="mcp-form">${fields}<label class="hp">Website<input name="website" autocomplete="off" tabindex="-1"></label>${form.consent_text ? `<p class="consent">${escapeHtml8(form.consent_text)}</p>` : ""}<button>${escapeHtml8(form.submit_label)}</button><div class="notice" role="status"></div></form><script>(()=>{const form=document.querySelector('#mcp-form'),notice=form.querySelector('.notice'),q=new URLSearchParams(location.search);form.addEventListener('submit',async event=>{event.preventDefault();const button=form.querySelector('button');button.disabled=true;const raw=Object.fromEntries(new FormData(form).entries()),website=String(raw.website||''),clickIds={};delete raw.website;for(const k of ['fbclid','gclid','gbraid','wbraid','ttclid','rdt_cid','msclkid']){const v=q.get(k);if(v)clickIds[k]=v}try{const response=await fetch('/analytics/forms/${escapeHtml8(form.public_id)}/submissions',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({data:raw,website,placementUrl:${JSON.stringify(placementUrl)},visitorId:q.get('visitor')||undefined,sessionId:q.get('session')||undefined,source:q.get('source')||undefined,medium:q.get('medium')||undefined,campaign:q.get('campaign')||undefined,clickIds})});if(!response.ok)throw new Error('submit');notice.textContent=${JSON.stringify(form.success_message)};notice.style.display='block';form.reset();${form.redirect_url ? `setTimeout(()=>{top.location.href=${JSON.stringify(form.redirect_url)}},700);` : ""}}catch{notice.textContent='Your response could not be submitted. Please try again.';notice.style.display='block'}finally{button.disabled=false}})})()</script></body></html>`;
|
|
78845
79489
|
}
|
|
78846
|
-
var import_hono34, import_factory6, import_zod56,
|
|
79490
|
+
var import_hono34, import_factory6, import_zod56, import_node_crypto52, import_papaparse6, analyticsApp, auth3, entitlementGuard, ThorbitApiKeySchema, ThorbitCallbackSchema, SiteInputSchema, PixelInputSchema, PixelUpdateSchema, EventSchema, IngestionSchema, ConversionSchema, ExportSchema2, CampaignLinkSchema, FormFieldSchema, FormInputSchema, FormSubmissionSchema, CrmImportSchema, ActivationDestinationSchema, BusinessModelSchema, AdSpendSchema;
|
|
78847
79491
|
var init_analytics_routes = __esm({
|
|
78848
79492
|
"src/api/analytics-routes.ts"() {
|
|
78849
79493
|
"use strict";
|
|
78850
79494
|
import_hono34 = require("hono");
|
|
78851
79495
|
import_factory6 = require("hono/factory");
|
|
78852
79496
|
import_zod56 = require("zod");
|
|
78853
|
-
|
|
79497
|
+
import_node_crypto52 = require("crypto");
|
|
78854
79498
|
import_papaparse6 = __toESM(require("papaparse"), 1);
|
|
78855
79499
|
init_api_auth();
|
|
78856
79500
|
init_db();
|
|
@@ -79181,7 +79825,7 @@ var init_analytics_routes = __esm({
|
|
|
79181
79825
|
const lastName = typeof data.last_name === "string" ? data.last_name.trim() : "";
|
|
79182
79826
|
const fullName = [firstName, lastName].filter(Boolean).join(" ") || (typeof data.name === "string" ? data.name.trim() : "") || email || "Website lead";
|
|
79183
79827
|
const identitySeed = email || `${fullName}:${Date.now()}`;
|
|
79184
|
-
const suffix2 = (0,
|
|
79828
|
+
const suffix2 = (0, import_node_crypto52.createHash)("sha256").update(identitySeed).digest("hex").slice(0, 12);
|
|
79185
79829
|
const path6 = `Leads/person-${suffix2}`;
|
|
79186
79830
|
const { key: memoryKey, error: memoryKeyError } = await getOrCreateUserMemoryKey(user);
|
|
79187
79831
|
const existing = memoryKey ? await memoryCall("getTool", { vault: "People", path: path6 }, memoryKey) : { ok: false, error: memoryKeyError || "memory_credential_unavailable" };
|
|
@@ -79280,9 +79924,9 @@ Submitted the published form.
|
|
|
79280
79924
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
79281
79925
|
});
|
|
79282
79926
|
const match = {
|
|
79283
|
-
...email ? { emailSha256: (0,
|
|
79927
|
+
...email ? { emailSha256: (0, import_node_crypto52.createHash)("sha256").update(email).digest("hex") } : {},
|
|
79284
79928
|
...phone ? {
|
|
79285
|
-
phoneSha256: (0,
|
|
79929
|
+
phoneSha256: (0, import_node_crypto52.createHash)("sha256").update(phone.replace(/\D/g, "")).digest("hex")
|
|
79286
79930
|
} : {}
|
|
79287
79931
|
};
|
|
79288
79932
|
const activationQueued = await queueAnalyticsActivation({
|
|
@@ -79710,7 +80354,7 @@ Submitted the published form.
|
|
|
79710
80354
|
rejectedCount += 1;
|
|
79711
80355
|
continue;
|
|
79712
80356
|
}
|
|
79713
|
-
const digest2 = (0,
|
|
80357
|
+
const digest2 = (0, import_node_crypto52.createHash)("sha256").update(
|
|
79714
80358
|
`${parsed.data.sourceSystem}:${externalId || email || phone || `${fullName}:${index}`}`
|
|
79715
80359
|
).digest("hex").slice(0, 16);
|
|
79716
80360
|
const path6 = `Leads/person-${digest2}`;
|
|
@@ -80168,19 +80812,19 @@ var init_analytics_delivery = __esm({
|
|
|
80168
80812
|
|
|
80169
80813
|
// src/api/scheduled-artifact-owner.ts
|
|
80170
80814
|
function scheduledArtifactOwnerIdForApiKey(apiKey) {
|
|
80171
|
-
return (0,
|
|
80815
|
+
return (0, import_node_crypto53.createHash)("sha256").update(apiKey).digest("hex").slice(0, 24);
|
|
80172
80816
|
}
|
|
80173
|
-
var
|
|
80817
|
+
var import_node_crypto53;
|
|
80174
80818
|
var init_scheduled_artifact_owner = __esm({
|
|
80175
80819
|
"src/api/scheduled-artifact-owner.ts"() {
|
|
80176
80820
|
"use strict";
|
|
80177
|
-
|
|
80821
|
+
import_node_crypto53 = require("crypto");
|
|
80178
80822
|
}
|
|
80179
80823
|
});
|
|
80180
80824
|
|
|
80181
80825
|
// src/api/scheduled-run-view-links.ts
|
|
80182
80826
|
async function ensureScheduledRunViewLinksSchema() {
|
|
80183
|
-
if (
|
|
80827
|
+
if (schemaReady3) return;
|
|
80184
80828
|
const db = getDb();
|
|
80185
80829
|
await db.execute(`
|
|
80186
80830
|
CREATE TABLE IF NOT EXISTS scheduled_run_view_links (
|
|
@@ -80228,10 +80872,10 @@ async function ensureScheduledRunViewLinksSchema() {
|
|
|
80228
80872
|
CREATE INDEX IF NOT EXISTS scheduled_run_view_links_expiry
|
|
80229
80873
|
ON scheduled_run_view_links(expires_at, revoked_at)
|
|
80230
80874
|
`);
|
|
80231
|
-
|
|
80875
|
+
schemaReady3 = true;
|
|
80232
80876
|
}
|
|
80233
80877
|
function tokenHash2(token6) {
|
|
80234
|
-
return (0,
|
|
80878
|
+
return (0, import_node_crypto54.createHash)("sha256").update(token6).digest("hex");
|
|
80235
80879
|
}
|
|
80236
80880
|
function mapRow(row) {
|
|
80237
80881
|
return {
|
|
@@ -80251,9 +80895,9 @@ function mapRow(row) {
|
|
|
80251
80895
|
async function createScheduledRunViewLink(input) {
|
|
80252
80896
|
await ensureScheduledRunViewLinksSchema();
|
|
80253
80897
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
80254
|
-
const token6 = (0,
|
|
80898
|
+
const token6 = (0, import_node_crypto54.randomBytes)(32).toString("base64url");
|
|
80255
80899
|
const record = {
|
|
80256
|
-
shareId: (0,
|
|
80900
|
+
shareId: (0, import_node_crypto54.randomUUID)(),
|
|
80257
80901
|
ownerId: input.ownerId,
|
|
80258
80902
|
runId: input.runId,
|
|
80259
80903
|
artifactId: input.artifactId,
|
|
@@ -80316,13 +80960,13 @@ async function revokeScheduledRunViewLink(ownerId2, runId, shareId, now = /* @__
|
|
|
80316
80960
|
});
|
|
80317
80961
|
return result.rowsAffected > 0;
|
|
80318
80962
|
}
|
|
80319
|
-
var
|
|
80963
|
+
var import_node_crypto54, schemaReady3;
|
|
80320
80964
|
var init_scheduled_run_view_links = __esm({
|
|
80321
80965
|
"src/api/scheduled-run-view-links.ts"() {
|
|
80322
80966
|
"use strict";
|
|
80323
|
-
|
|
80967
|
+
import_node_crypto54 = require("crypto");
|
|
80324
80968
|
init_db();
|
|
80325
|
-
|
|
80969
|
+
schemaReady3 = false;
|
|
80326
80970
|
}
|
|
80327
80971
|
});
|
|
80328
80972
|
|
|
@@ -80386,15 +81030,15 @@ ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id=
|
|
|
80386
81030
|
html,
|
|
80387
81031
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
80388
81032
|
bytes,
|
|
80389
|
-
sha256: (0,
|
|
81033
|
+
sha256: (0, import_node_crypto55.createHash)("sha256").update(html).digest("hex"),
|
|
80390
81034
|
generatedAt: generatedAtIso
|
|
80391
81035
|
};
|
|
80392
81036
|
}
|
|
80393
|
-
var
|
|
81037
|
+
var import_node_crypto55;
|
|
80394
81038
|
var init_render2 = __esm({
|
|
80395
81039
|
"src/personal-authority/render.ts"() {
|
|
80396
81040
|
"use strict";
|
|
80397
|
-
|
|
81041
|
+
import_node_crypto55 = require("crypto");
|
|
80398
81042
|
}
|
|
80399
81043
|
});
|
|
80400
81044
|
|
|
@@ -80497,15 +81141,15 @@ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id
|
|
|
80497
81141
|
html,
|
|
80498
81142
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
80499
81143
|
bytes,
|
|
80500
|
-
sha256: (0,
|
|
81144
|
+
sha256: (0, import_node_crypto56.createHash)("sha256").update(html).digest("hex"),
|
|
80501
81145
|
generatedAt: generatedAtIso
|
|
80502
81146
|
};
|
|
80503
81147
|
}
|
|
80504
|
-
var
|
|
81148
|
+
var import_node_crypto56, FONT_STACKS;
|
|
80505
81149
|
var init_render_v2 = __esm({
|
|
80506
81150
|
"src/personal-authority/render-v2.ts"() {
|
|
80507
81151
|
"use strict";
|
|
80508
|
-
|
|
81152
|
+
import_node_crypto56 = require("crypto");
|
|
80509
81153
|
init_contracts();
|
|
80510
81154
|
FONT_STACKS = Object.freeze({
|
|
80511
81155
|
"editorial-serif": "Iowan Old Style, Baskerville, Times New Roman, serif",
|
|
@@ -80621,15 +81265,15 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
80621
81265
|
@media(max-width:620px){.desk-section__grid--panorama,.desk-section__grid--mosaic,.desk-section__grid--tiles{grid-template-columns:1fr}.story-card--panorama{display:block}.story-card--panorama h3,.story-card--mosaic-lead h3{font-size:34px}.story-card--mosaic-lead{grid-column:auto;grid-row:auto}.desk-section__grid--tiles>.story-card:nth-child(3n+2){margin-top:0}}
|
|
80622
81266
|
</style></head><body data-theme="${escapeHtml11(config.theme)}" id="top" data-scheduled-renderer="newsroom_publisher_v1">${ticker}${masthead}${navigation}<main>${leadGrid}${latest}${sections}${newsletter}${pressRoom}${trustCenter}</main>${trustFooter}</body></html>`;
|
|
80623
81267
|
const bytes = Buffer.byteLength(html);
|
|
80624
|
-
const sha2565 = (0,
|
|
81268
|
+
const sha2565 = (0, import_node_crypto57.createHash)("sha256").update(html).digest("hex");
|
|
80625
81269
|
const filename2 = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
|
|
80626
81270
|
return { html, filename: filename2, bytes, sha256: sha2565, generatedAt: generatedAtIso };
|
|
80627
81271
|
}
|
|
80628
|
-
var
|
|
81272
|
+
var import_node_crypto57;
|
|
80629
81273
|
var init_render3 = __esm({
|
|
80630
81274
|
"src/newsroom-publisher/render.ts"() {
|
|
80631
81275
|
"use strict";
|
|
80632
|
-
|
|
81276
|
+
import_node_crypto57 = require("crypto");
|
|
80633
81277
|
}
|
|
80634
81278
|
});
|
|
80635
81279
|
|
|
@@ -80721,7 +81365,7 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
80721
81365
|
:root{--ink:#10213d;--ink2:#1c355a;--blue:#2563eb;--blue2:#1749b6;--mint:#45d5aa;--paper:#f7f5f0;--line:#dce4ef;--card:#fff;--body:#475569;--serif:Iowan Old Style,Palatino Linotype,Palatino,Georgia,serif;--sans:Inter,Avenir Next,ui-sans-serif,system-ui,sans-serif}body[data-theme="slate"]{--ink:#1e293b;--ink2:#334155;--blue:#475569;--blue2:#1e293b;--mint:#94a3b8;--paper:#f8fafc}body[data-theme="forest"]{--ink:#12352e;--ink2:#23584c;--blue:#147d64;--blue2:#0c5b48;--mint:#79d8bd;--paper:#f4f8f3}*{box-sizing:border-box}html{scroll-behavior:smooth;background:var(--paper)}body{margin:0;color:#252a33;background:var(--paper);font-family:var(--sans);line-height:1.6}a{color:inherit}button{font:inherit}button:focus-visible,a:focus-visible{outline:3px solid var(--mint);outline-offset:3px}.progress{position:fixed;z-index:50;top:0;left:0;height:4px;width:0;background:var(--mint)}.hero{position:relative;overflow:hidden;color:#fff;background:var(--ink)}.hero:after{position:absolute;right:-110px;top:-150px;width:420px;height:420px;border:1px solid #ffffff1a;border-radius:50%;content:""}.hero-inner{position:relative;z-index:1;max-width:1240px;margin:auto;padding:58px 42px 126px}.breadcrumb{display:flex;gap:8px;margin-bottom:34px;color:#dbeafecc;font-size:14px}.eyebrow{display:block;color:var(--blue);font-size:12px;font-weight:800;letter-spacing:.16em;text-transform:uppercase}.hero .eyebrow{color:var(--mint)}h1,h2,h3,p{margin-top:0}.hero h1{max-width:1000px;margin:14px 0 24px;font:700 clamp(44px,6vw,78px)/.98 var(--serif);letter-spacing:-.035em}.hero .dek{max-width:780px;color:#dbeafe;font-size:20px}.contributors{margin-top:30px;color:#eff6ff;font-size:14px}.contributors a{font-weight:800}.meta{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:#dbeafecc}.layout{position:relative;z-index:2;display:grid;grid-template-columns:minmax(0,760px) 290px;gap:64px;max-width:1240px;margin:-78px auto 0;padding:0 42px 80px}.main{min-width:0}.takeaways{padding:38px 44px;border-radius:24px;background:#fff;box-shadow:0 24px 70px #10213d24}.takeaways h2{margin:5px 0 20px;font:700 32px/1.1 var(--serif);color:var(--ink)}.takeaways ul{display:grid;gap:16px;margin:0;padding:0;list-style:none}.takeaways li{position:relative;padding-left:26px;color:var(--body);font-size:17px}.takeaways li:before{position:absolute;left:2px;top:.7em;width:8px;height:8px;border-radius:50%;background:var(--blue);content:""}.intro{padding:40px 0 4px}.intro p,.article-section>p{margin-bottom:22px;color:var(--body);font:400 18px/1.75 var(--sans)}.article-section{scroll-margin-top:28px;padding-top:45px}.article-section h2,.faq h2{margin:6px 0 20px;color:var(--ink);font:700 38px/1.08 var(--serif);letter-spacing:-.02em}.article-section ul{display:grid;gap:10px;margin:22px 0;padding-left:24px;color:var(--body);font-size:17px}.article-section li::marker{color:var(--blue)}.callout{margin:34px 0;padding:24px 28px;border-left:4px solid var(--blue);border-radius:0 16px 16px 0;background:#fff}.callout span{color:var(--blue);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.callout h3{margin:5px 0 8px;color:var(--ink);font:700 24px/1.15 var(--serif)}.callout p{margin:0;color:var(--body)}.rail{padding-top:0}.sidebar-media{overflow:hidden;margin:0 0 18px;border:1px solid #dbeafe;border-radius:16px;background:#fff}.sidebar-media img,.sidebar-media svg{display:block;width:100%;aspect-ratio:16/9;object-fit:cover}.sidebar-media figcaption{padding:10px 13px;color:#64748b;font-size:11px}.disclosure{margin-bottom:28px;border-top:1px solid #dbeafe;border-bottom:1px solid #dbeafe}.disclosure button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:14px;padding:15px 0;border:0;color:#64748b;background:transparent;text-align:left;font-size:12px;cursor:pointer}.disclosure button b{color:var(--blue);font-size:18px;transition:transform .2s}.disclosure button[aria-expanded="true"] b{transform:rotate(180deg)}.disclosure p{padding:0 0 16px;margin:0;color:#64748b;font-size:12px}.toc{position:sticky;top:30px;padding:22px;border:1px solid var(--line);border-radius:16px;background:#fff;box-shadow:0 2px 5px #10213d12}.toc header{display:flex;align-items:center;justify-content:space-between}.toc header strong{color:var(--ink);font:700 21px/1 var(--serif)}.toc header button{width:34px;height:34px;border:0;border-radius:50%;color:var(--blue);background:transparent;cursor:pointer}.toc nav{display:grid;margin-top:14px}.toc nav a{display:flex;align-items:flex-start;gap:11px;padding:8px 0;color:#64748b;text-decoration:none;font-size:13px;line-height:1.35}.toc nav i{width:8px;height:8px;margin-top:5px;border:2px solid #bfdbfe;border-radius:50%}.toc nav a[aria-current="location"]{color:var(--ink);font-weight:800}.toc nav a[aria-current="location"] i{border-color:var(--blue);background:var(--blue)}.back-top{width:100%;margin-top:18px;padding:16px 0 0;border:0;border-top:1px solid var(--line);color:var(--blue);background:transparent;text-align:right;font-size:13px;font-weight:800;cursor:pointer}.faq{scroll-margin-top:28px;padding-top:64px}.faq>div{border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.faq article+article{border-top:1px solid var(--line)}.faq h3{margin:0}.faq h3 button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:18px;padding:19px 0;border:0;color:var(--ink);background:transparent;text-align:left;font-weight:800;cursor:pointer}.faq h3 b{color:var(--blue);font-size:22px}.faq article>p{padding:0 0 20px;margin:0;color:var(--body);font-size:16px}.author-card{margin-top:64px;padding:32px 36px;border-radius:18px;background:#fff}.article-actions{display:flex;flex-wrap:wrap;justify-content:space-between;gap:14px}.article-actions button{display:inline-flex;min-height:46px;align-items:center;justify-content:center;gap:8px;padding:8px 18px;border:2px solid var(--blue);border-radius:999px;color:var(--ink);background:#fff;font-weight:800;cursor:pointer}.article-actions button:hover{color:#fff;background:var(--blue)}.action-status{min-height:20px;margin:8px 0 0;color:var(--blue);text-align:right;font-size:13px;font-weight:700}.author-grid{display:grid;grid-template-columns:auto 1fr auto;gap:22px;align-items:center;margin-top:24px}.author-portrait{width:88px;height:88px;border-radius:50%;object-fit:cover}.author-initials{display:grid;place-items:center;color:var(--ink);background:#fecdd3;font-size:22px;font-weight:900}.author-grid span{color:#64748b;font-size:13px}.author-grid h2{margin:2px 0;color:var(--ink);font:700 27px/1 var(--serif)}.author-grid h2 a{text-decoration:none}.author-grid p{margin:8px 0;color:#64748b;font-size:14px}.author-grid nav{display:flex;flex-wrap:wrap;gap:14px}.author-grid nav a{color:#64748b;font-size:12px}.author-more{display:inline-flex;min-height:48px;align-items:center;justify-content:center;padding:10px 24px;border:2px solid var(--blue);color:var(--blue);text-align:center;text-decoration:none;font-size:13px;font-weight:800}.author-bio{margin:24px 0 0!important;padding-top:20px;border-top:1px solid var(--line);color:var(--body);font-size:16px}dialog{width:min(720px,calc(100% - 30px));max-height:calc(100dvh - 30px);padding:0;border:0;border-radius:18px;color:var(--ink);background:#fff;box-shadow:0 24px 70px #10213d38}dialog::backdrop{background:#0f172a7a;backdrop-filter:blur(2px)}dialog>div{position:relative;padding:30px}dialog h2{margin:0 50px 2px 0;font:700 30px/1.1 var(--serif)}dialog>div>p{color:#64748b}.dialog-close{position:absolute;top:13px;right:13px;width:44px;height:44px;border:0;border-radius:50%;color:var(--blue);background:transparent;font-size:29px;cursor:pointer}dialog section{border-top:1px solid var(--line)}dialog section button{display:block;width:100%;padding:17px 5px;border:0;border-bottom:1px solid var(--line);color:var(--body);background:#fff;text-align:left;line-height:1.65;cursor:pointer}.citation-status{min-height:22px;margin:14px 0 0!important;color:var(--blue)!important;font-size:13px;font-weight:800}.generated{max-width:1156px;margin:-52px auto 50px;padding:0 42px;color:#94a3b8;font-size:11px}@media(max-width:900px){.layout{display:block}.rail{display:none}.hero-inner{padding-bottom:116px}}@media(max-width:620px){.hero-inner{padding:36px 20px 104px}.hero h1{font-size:46px}.hero .dek{font-size:17px}.layout{margin-top:-70px;padding:0 16px 54px}.takeaways{padding:28px 24px}.article-section h2,.faq h2{font-size:32px}.author-card{padding:24px}.article-actions{display:grid;justify-content:start}.author-grid{grid-template-columns:1fr;gap:12px}.author-more{width:100%}dialog>div{padding:24px}.generated{padding:0 20px}}
|
|
80722
81366
|
</style></head><body data-theme="${escapeHtml12(config.theme)}" data-scheduled-renderer="blog_article_v1"><div class="progress" aria-hidden="true"></div><header class="hero"><div class="hero-inner"><nav class="breadcrumb" aria-label="Breadcrumb"><a href="${safeHref4(input.canonicalUrl)}">${escapeHtml12(input.category)}</a><span>/</span><span>Article</span></nav><span class="eyebrow">${escapeHtml12(input.eyebrow)}</span><h1>${escapeHtml12(input.title)}</h1>${input.dek ? `<p class="dek">${escapeHtml12(input.dek)}</p>` : ""}<div class="contributors">${contributorText}<div class="meta"><time datetime="${escapeHtml12(articleDate)}">Updated ${formatDate2(articleDate)}</time><span>\u2022</span><span>${input.readTimeMinutes} min read</span>${input.reviewer ? "<span>\u2022</span><strong>Expert reviewed</strong>" : ""}</div></div></div></header><main class="layout"><article class="main"><section class="takeaways"><span class="eyebrow">The short answer</span><h2>Key takeaways</h2><ul>${input.keyTakeaways.map((item) => `<li>${escapeHtml12(item)}</li>`).join("")}</ul></section><section class="intro">${input.introduction.map((paragraph) => `<p>${escapeHtml12(paragraph)}</p>`).join("")}</section>${sections}${faq}${author}</article><div class="rail">${media}${disclosure}${toc}</div></main>${config.showGeneratedAt ? `<p class="generated">Rendered ${formatDate2(generatedAtIso)} by MCP Scraper.</p>` : ""}${citationDialog}<script>(()=>{const citations=${jsonForScript(citationValues)};const canonical=${jsonForScript(input.canonicalUrl)};const title=${jsonForScript(input.title)};const progress=document.querySelector('.progress');const tocLinks=[...document.querySelectorAll('.toc nav a')];const targets=tocLinks.map(link=>document.querySelector(link.hash)).filter(Boolean);const update=()=>{const max=document.documentElement.scrollHeight-innerHeight;if(progress)progress.style.width=(max>0?scrollY/max*100:0)+'%';let active=targets[0]?.id;for(const target of targets){if(target.getBoundingClientRect().top<=innerHeight*.55)active=target.id}tocLinks.forEach(link=>link.toggleAttribute('aria-current',link.hash==='#'+active));tocLinks.forEach(link=>{if(link.hash==='#'+active)link.setAttribute('aria-current','location');else link.removeAttribute('aria-current')})};addEventListener('scroll',update,{passive:true});addEventListener('resize',update);update();document.querySelectorAll('.faq h3 button').forEach(button=>button.addEventListener('click',()=>{const panel=document.getElementById(button.getAttribute('aria-controls'));const open=button.getAttribute('aria-expanded')==='true';button.setAttribute('aria-expanded',String(!open));panel.hidden=open;button.querySelector('b').textContent=open?'+':'\u2212'}));const disclosure=document.querySelector('.disclosure button');disclosure?.addEventListener('click',()=>{const panel=document.getElementById(disclosure.getAttribute('aria-controls'));const open=disclosure.getAttribute('aria-expanded')==='true';disclosure.setAttribute('aria-expanded',String(!open));panel.hidden=open});const tocToggle=document.querySelector('.toc header button');tocToggle?.addEventListener('click',()=>{const nav=document.getElementById('toc-links');const open=tocToggle.getAttribute('aria-expanded')==='true';tocToggle.setAttribute('aria-expanded',String(!open));nav.hidden=open;tocToggle.textContent=open?'\u2304':'\u2303'});document.querySelector('.back-top')?.addEventListener('click',()=>scrollTo({top:0,behavior:'smooth'}));const copy=async text=>{try{await navigator.clipboard.writeText(text)}catch{const area=document.createElement('textarea');area.value=text;area.style.position='fixed';area.style.opacity='0';document.body.append(area);area.select();document.execCommand('copy');area.remove()}};const dialog=document.getElementById('citation-dialog');document.querySelector('[data-cite]')?.addEventListener('click',()=>dialog.showModal());document.querySelector('.dialog-close')?.addEventListener('click',()=>dialog.close());dialog?.addEventListener('click',event=>{if(event.target===dialog)dialog.close()});document.querySelectorAll('[data-citation]').forEach(button=>button.addEventListener('click',async()=>{const style=button.dataset.citation;await copy(citations[style]);document.querySelector('.citation-status').textContent=style+' citation copied to clipboard.'}));document.querySelector('[data-share]')?.addEventListener('click',async()=>{const status=document.querySelector('.action-status');if(navigator.share){try{await navigator.share({title,url:canonical});status.textContent='Sharing options opened.';return}catch(error){if(error.name==='AbortError')return}}await copy(canonical);status.textContent='Article link copied to clipboard.'})})()</script></body></html>`;
|
|
80723
81367
|
const bytes = Buffer.byteLength(html);
|
|
80724
|
-
const sha2565 = (0,
|
|
81368
|
+
const sha2565 = (0, import_node_crypto58.createHash)("sha256").update(html).digest("hex");
|
|
80725
81369
|
return {
|
|
80726
81370
|
html,
|
|
80727
81371
|
filename: "blog-article.html",
|
|
@@ -80731,11 +81375,11 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
80731
81375
|
generatedAt: generatedAtIso
|
|
80732
81376
|
};
|
|
80733
81377
|
}
|
|
80734
|
-
var
|
|
81378
|
+
var import_node_crypto58;
|
|
80735
81379
|
var init_render4 = __esm({
|
|
80736
81380
|
"src/blog-article/render.ts"() {
|
|
80737
81381
|
"use strict";
|
|
80738
|
-
|
|
81382
|
+
import_node_crypto58 = require("crypto");
|
|
80739
81383
|
}
|
|
80740
81384
|
});
|
|
80741
81385
|
|
|
@@ -81066,7 +81710,7 @@ function policy6() {
|
|
|
81066
81710
|
};
|
|
81067
81711
|
}
|
|
81068
81712
|
function runStorageSegment(runId) {
|
|
81069
|
-
return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${(0,
|
|
81713
|
+
return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${(0, import_node_crypto59.createHash)("sha256").update(runId).digest("hex").slice(0, 32)}`;
|
|
81070
81714
|
}
|
|
81071
81715
|
async function createScheduledRunArtifact(args) {
|
|
81072
81716
|
if (args.rendered.bytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) {
|
|
@@ -81107,12 +81751,12 @@ async function readScheduledRunArtifact(args) {
|
|
|
81107
81751
|
if (!window2 || window2.nextOffset !== null || window2.totalBytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) return null;
|
|
81108
81752
|
return window2.text;
|
|
81109
81753
|
}
|
|
81110
|
-
var
|
|
81754
|
+
var import_node_crypto59, SCHEDULED_RUN_ARTIFACT_PREFIX, SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS, SCHEDULED_RUN_ARTIFACT_MAX_BYTES;
|
|
81111
81755
|
var init_scheduled_run_artifact_store = __esm({
|
|
81112
81756
|
"src/scheduled-artifacts/scheduled-run-artifact-store.ts"() {
|
|
81113
81757
|
"use strict";
|
|
81114
81758
|
init_private_artifacts();
|
|
81115
|
-
|
|
81759
|
+
import_node_crypto59 = require("crypto");
|
|
81116
81760
|
SCHEDULED_RUN_ARTIFACT_PREFIX = "scheduled-run-artifacts/";
|
|
81117
81761
|
SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS = 15 * 60 * 1e3;
|
|
81118
81762
|
SCHEDULED_RUN_ARTIFACT_MAX_BYTES = 2e6;
|
|
@@ -81190,357 +81834,6 @@ var init_public_scheduled_result_routes = __esm({
|
|
|
81190
81834
|
}
|
|
81191
81835
|
});
|
|
81192
81836
|
|
|
81193
|
-
// src/api/service-connections.ts
|
|
81194
|
-
function ensureServiceConnectionsSchema() {
|
|
81195
|
-
const currentDb = getDb();
|
|
81196
|
-
if (schemaReady3 && schemaDb6 === currentDb) return schemaReady3;
|
|
81197
|
-
schemaDb6 = currentDb;
|
|
81198
|
-
schemaReady3 = (async () => {
|
|
81199
|
-
const db = currentDb;
|
|
81200
|
-
await db.execute(`
|
|
81201
|
-
CREATE TABLE IF NOT EXISTS service_connections (
|
|
81202
|
-
id TEXT PRIMARY KEY,
|
|
81203
|
-
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
81204
|
-
provider_config_key TEXT NOT NULL,
|
|
81205
|
-
provider TEXT,
|
|
81206
|
-
transport TEXT NOT NULL,
|
|
81207
|
-
upstream_connection_id TEXT,
|
|
81208
|
-
label TEXT,
|
|
81209
|
-
user_label TEXT,
|
|
81210
|
-
provider_account_id TEXT,
|
|
81211
|
-
provider_account_email TEXT,
|
|
81212
|
-
provider_account_name TEXT,
|
|
81213
|
-
provider_identity_checked_at TEXT,
|
|
81214
|
-
provider_identity_source_updated_at TEXT,
|
|
81215
|
-
lifecycle_status TEXT NOT NULL DEFAULT 'pending',
|
|
81216
|
-
operational_status TEXT NOT NULL DEFAULT 'unknown',
|
|
81217
|
-
reconnect_required INTEGER NOT NULL DEFAULT 0,
|
|
81218
|
-
actions_enabled INTEGER NOT NULL DEFAULT 0,
|
|
81219
|
-
read_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
81220
|
-
action_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
81221
|
-
tool_revision TEXT,
|
|
81222
|
-
last_checked_at TEXT,
|
|
81223
|
-
last_successful_call_at TEXT,
|
|
81224
|
-
last_failure_at TEXT,
|
|
81225
|
-
last_failure_code TEXT,
|
|
81226
|
-
last_failure_retryable INTEGER,
|
|
81227
|
-
consecutive_failures INTEGER NOT NULL DEFAULT 0,
|
|
81228
|
-
vault_name TEXT,
|
|
81229
|
-
table_name TEXT,
|
|
81230
|
-
legacy_owner_identity TEXT,
|
|
81231
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
81232
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
81233
|
-
UNIQUE(user_id, provider_config_key, upstream_connection_id)
|
|
81234
|
-
)
|
|
81235
|
-
`);
|
|
81236
|
-
try {
|
|
81237
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN user_label TEXT`);
|
|
81238
|
-
} catch {
|
|
81239
|
-
}
|
|
81240
|
-
try {
|
|
81241
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_id TEXT`);
|
|
81242
|
-
} catch {
|
|
81243
|
-
}
|
|
81244
|
-
try {
|
|
81245
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_email TEXT`);
|
|
81246
|
-
} catch {
|
|
81247
|
-
}
|
|
81248
|
-
try {
|
|
81249
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_name TEXT`);
|
|
81250
|
-
} catch {
|
|
81251
|
-
}
|
|
81252
|
-
try {
|
|
81253
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_identity_checked_at TEXT`);
|
|
81254
|
-
} catch {
|
|
81255
|
-
}
|
|
81256
|
-
try {
|
|
81257
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_identity_source_updated_at TEXT`);
|
|
81258
|
-
} catch {
|
|
81259
|
-
}
|
|
81260
|
-
await db.execute(`CREATE INDEX IF NOT EXISTS service_connections_user_updated ON service_connections(user_id, updated_at DESC)`);
|
|
81261
|
-
await db.execute(`CREATE INDEX IF NOT EXISTS service_connections_upstream ON service_connections(provider_config_key, upstream_connection_id)`);
|
|
81262
|
-
await db.execute(`
|
|
81263
|
-
CREATE TABLE IF NOT EXISTS service_connection_health_events (
|
|
81264
|
-
id TEXT PRIMARY KEY,
|
|
81265
|
-
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
81266
|
-
operational_status TEXT NOT NULL,
|
|
81267
|
-
failure_code TEXT,
|
|
81268
|
-
retryable INTEGER,
|
|
81269
|
-
evidence_source TEXT NOT NULL,
|
|
81270
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
81271
|
-
)
|
|
81272
|
-
`);
|
|
81273
|
-
await db.execute(`CREATE INDEX IF NOT EXISTS service_connection_health_events_connection ON service_connection_health_events(connection_id, created_at DESC)`);
|
|
81274
|
-
await db.execute(`
|
|
81275
|
-
CREATE TABLE IF NOT EXISTS service_connection_action_audit (
|
|
81276
|
-
id TEXT PRIMARY KEY,
|
|
81277
|
-
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
81278
|
-
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
81279
|
-
tool TEXT NOT NULL,
|
|
81280
|
-
request_id TEXT NOT NULL,
|
|
81281
|
-
status TEXT NOT NULL,
|
|
81282
|
-
error_code TEXT,
|
|
81283
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
81284
|
-
UNIQUE(user_id, request_id)
|
|
81285
|
-
)
|
|
81286
|
-
`);
|
|
81287
|
-
try {
|
|
81288
|
-
await db.execute(`ALTER TABLE service_connection_action_audit ADD COLUMN request_digest TEXT`);
|
|
81289
|
-
} catch {
|
|
81290
|
-
}
|
|
81291
|
-
try {
|
|
81292
|
-
await db.execute(`ALTER TABLE service_connection_action_audit ADD COLUMN result_json TEXT`);
|
|
81293
|
-
} catch {
|
|
81294
|
-
}
|
|
81295
|
-
})().catch((error) => {
|
|
81296
|
-
schemaReady3 = null;
|
|
81297
|
-
schemaDb6 = null;
|
|
81298
|
-
throw error;
|
|
81299
|
-
});
|
|
81300
|
-
return schemaReady3;
|
|
81301
|
-
}
|
|
81302
|
-
function parseTools(value) {
|
|
81303
|
-
if (typeof value !== "string") return [];
|
|
81304
|
-
try {
|
|
81305
|
-
const parsed = JSON.parse(value);
|
|
81306
|
-
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
81307
|
-
} catch {
|
|
81308
|
-
return [];
|
|
81309
|
-
}
|
|
81310
|
-
}
|
|
81311
|
-
function rowToRecord(row) {
|
|
81312
|
-
return {
|
|
81313
|
-
id: String(row.id),
|
|
81314
|
-
userId: Number(row.user_id),
|
|
81315
|
-
providerConfigKey: String(row.provider_config_key),
|
|
81316
|
-
provider: typeof row.provider === "string" ? row.provider : null,
|
|
81317
|
-
transport: row.transport === "remote_mcp" ? "remote_mcp" : "nango",
|
|
81318
|
-
upstreamConnectionId: typeof row.upstream_connection_id === "string" ? row.upstream_connection_id : null,
|
|
81319
|
-
label: typeof row.label === "string" ? row.label : null,
|
|
81320
|
-
userLabel: typeof row.user_label === "string" ? row.user_label : null,
|
|
81321
|
-
providerAccountId: typeof row.provider_account_id === "string" ? row.provider_account_id : null,
|
|
81322
|
-
providerAccountEmail: typeof row.provider_account_email === "string" ? row.provider_account_email : null,
|
|
81323
|
-
providerAccountName: typeof row.provider_account_name === "string" ? row.provider_account_name : null,
|
|
81324
|
-
providerIdentityCheckedAt: typeof row.provider_identity_checked_at === "string" ? row.provider_identity_checked_at : null,
|
|
81325
|
-
providerIdentitySourceUpdatedAt: typeof row.provider_identity_source_updated_at === "string" ? row.provider_identity_source_updated_at : null,
|
|
81326
|
-
lifecycleStatus: String(row.lifecycle_status),
|
|
81327
|
-
operationalStatus: String(row.operational_status),
|
|
81328
|
-
reconnectRequired: Number(row.reconnect_required) === 1,
|
|
81329
|
-
actionsEnabled: Number(row.actions_enabled) === 1,
|
|
81330
|
-
readTools: parseTools(row.read_tools_json),
|
|
81331
|
-
actionTools: parseTools(row.action_tools_json),
|
|
81332
|
-
toolRevision: typeof row.tool_revision === "string" ? row.tool_revision : null,
|
|
81333
|
-
lastCheckedAt: typeof row.last_checked_at === "string" ? row.last_checked_at : null,
|
|
81334
|
-
lastSuccessfulCallAt: typeof row.last_successful_call_at === "string" ? row.last_successful_call_at : null,
|
|
81335
|
-
lastFailureAt: typeof row.last_failure_at === "string" ? row.last_failure_at : null,
|
|
81336
|
-
lastFailureCode: typeof row.last_failure_code === "string" ? row.last_failure_code : null,
|
|
81337
|
-
lastFailureRetryable: row.last_failure_retryable === null || row.last_failure_retryable === void 0 ? null : Number(row.last_failure_retryable) === 1,
|
|
81338
|
-
consecutiveFailures: Number(row.consecutive_failures ?? 0),
|
|
81339
|
-
vaultName: typeof row.vault_name === "string" ? row.vault_name : null,
|
|
81340
|
-
tableName: typeof row.table_name === "string" ? row.table_name : null,
|
|
81341
|
-
createdAt: String(row.created_at),
|
|
81342
|
-
updatedAt: String(row.updated_at)
|
|
81343
|
-
};
|
|
81344
|
-
}
|
|
81345
|
-
async function userIdForIdentity(identity) {
|
|
81346
|
-
const user = await getUserByEmail(identity.normalize("NFKC").trim().toLowerCase());
|
|
81347
|
-
if (!user) throw new Error("service_connection_user_not_found");
|
|
81348
|
-
return Number(user.id);
|
|
81349
|
-
}
|
|
81350
|
-
async function reconcileDiscoveredNangoConnections(identity, discovered) {
|
|
81351
|
-
await ensureServiceConnectionsSchema();
|
|
81352
|
-
const db = getDb();
|
|
81353
|
-
const userId = await userIdForIdentity(identity);
|
|
81354
|
-
for (const connection of discovered) {
|
|
81355
|
-
await db.execute({
|
|
81356
|
-
sql: `
|
|
81357
|
-
INSERT INTO service_connections (
|
|
81358
|
-
id, user_id, provider_config_key, provider, transport, upstream_connection_id,
|
|
81359
|
-
label, lifecycle_status, reconnect_required, actions_enabled, legacy_owner_identity, created_at, updated_at
|
|
81360
|
-
) VALUES (?, ?, ?, ?, 'nango', ?, ?, ?, ?, 1, ?, COALESCE(?, datetime('now')), COALESCE(?, datetime('now')))
|
|
81361
|
-
ON CONFLICT(user_id, provider_config_key, upstream_connection_id) DO UPDATE SET
|
|
81362
|
-
provider = excluded.provider,
|
|
81363
|
-
label = COALESCE(excluded.label, service_connections.label),
|
|
81364
|
-
lifecycle_status = excluded.lifecycle_status,
|
|
81365
|
-
reconnect_required = excluded.reconnect_required,
|
|
81366
|
-
updated_at = excluded.updated_at
|
|
81367
|
-
`,
|
|
81368
|
-
args: [
|
|
81369
|
-
(0, import_node_crypto59.randomUUID)(),
|
|
81370
|
-
userId,
|
|
81371
|
-
connection.providerConfigKey,
|
|
81372
|
-
connection.provider,
|
|
81373
|
-
connection.upstreamConnectionId,
|
|
81374
|
-
connection.label,
|
|
81375
|
-
connection.lifecycleStatus,
|
|
81376
|
-
connection.reconnectRequired ? 1 : 0,
|
|
81377
|
-
identity,
|
|
81378
|
-
connection.createdAt,
|
|
81379
|
-
connection.updatedAt
|
|
81380
|
-
]
|
|
81381
|
-
});
|
|
81382
|
-
}
|
|
81383
|
-
return listServiceConnections(identity, "nango");
|
|
81384
|
-
}
|
|
81385
|
-
async function listServiceConnections(identity, transport) {
|
|
81386
|
-
await ensureServiceConnectionsSchema();
|
|
81387
|
-
const userId = await userIdForIdentity(identity);
|
|
81388
|
-
const result = await getDb().execute({
|
|
81389
|
-
sql: `SELECT * FROM service_connections WHERE user_id = ?${transport ? " AND transport = ?" : ""} AND lifecycle_status <> 'disconnected' ORDER BY updated_at DESC`,
|
|
81390
|
-
args: transport ? [userId, transport] : [userId]
|
|
81391
|
-
});
|
|
81392
|
-
return result.rows.map((row) => rowToRecord(row));
|
|
81393
|
-
}
|
|
81394
|
-
async function getOwnedServiceConnection(identity, connectionId) {
|
|
81395
|
-
await ensureServiceConnectionsSchema();
|
|
81396
|
-
const userId = await userIdForIdentity(identity);
|
|
81397
|
-
const result = await getDb().execute({
|
|
81398
|
-
sql: "SELECT * FROM service_connections WHERE id = ? AND user_id = ? LIMIT 1",
|
|
81399
|
-
args: [connectionId, userId]
|
|
81400
|
-
});
|
|
81401
|
-
const row = result.rows[0];
|
|
81402
|
-
return row ? rowToRecord(row) : null;
|
|
81403
|
-
}
|
|
81404
|
-
async function updateServiceConnectionTools(connectionId, readTools, actionTools, toolRevision) {
|
|
81405
|
-
await ensureServiceConnectionsSchema();
|
|
81406
|
-
await getDb().execute({
|
|
81407
|
-
sql: `UPDATE service_connections SET read_tools_json = ?, action_tools_json = ?, tool_revision = ?, updated_at = datetime('now') WHERE id = ?`,
|
|
81408
|
-
args: [JSON.stringify(readTools), JSON.stringify(actionTools), toolRevision, connectionId]
|
|
81409
|
-
});
|
|
81410
|
-
}
|
|
81411
|
-
async function setServiceConnectionProviderIdentity(args) {
|
|
81412
|
-
await ensureServiceConnectionsSchema();
|
|
81413
|
-
await getDb().execute({
|
|
81414
|
-
sql: `
|
|
81415
|
-
UPDATE service_connections SET
|
|
81416
|
-
provider_account_id = ?, provider_account_email = ?, provider_account_name = ?,
|
|
81417
|
-
provider_identity_checked_at = datetime('now'), provider_identity_source_updated_at = ?,
|
|
81418
|
-
updated_at = datetime('now')
|
|
81419
|
-
WHERE id = ?
|
|
81420
|
-
`,
|
|
81421
|
-
args: [
|
|
81422
|
-
args.providerAccountId ?? null,
|
|
81423
|
-
args.providerAccountEmail?.toLowerCase() ?? null,
|
|
81424
|
-
args.providerAccountName ?? null,
|
|
81425
|
-
args.sourceUpdatedAt,
|
|
81426
|
-
args.connectionId
|
|
81427
|
-
]
|
|
81428
|
-
});
|
|
81429
|
-
}
|
|
81430
|
-
async function setServiceConnectionUserLabel(identity, connectionId, userLabel) {
|
|
81431
|
-
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
81432
|
-
if (!connection || connection.lifecycleStatus === "disconnected") throw new Error("service_connection_not_found");
|
|
81433
|
-
await getDb().execute({
|
|
81434
|
-
sql: `UPDATE service_connections SET user_label = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
81435
|
-
args: [userLabel, connectionId, connection.userId]
|
|
81436
|
-
});
|
|
81437
|
-
return userLabel;
|
|
81438
|
-
}
|
|
81439
|
-
async function recordServiceConnectionHealth(args) {
|
|
81440
|
-
await ensureServiceConnectionsSchema();
|
|
81441
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
81442
|
-
await getDb().execute({
|
|
81443
|
-
sql: `
|
|
81444
|
-
UPDATE service_connections SET
|
|
81445
|
-
operational_status = ?, last_checked_at = ?,
|
|
81446
|
-
last_successful_call_at = CASE WHEN ? = 'available' THEN ? ELSE last_successful_call_at END,
|
|
81447
|
-
last_failure_at = CASE WHEN ? IN ('degraded', 'unavailable') THEN ? ELSE NULL END,
|
|
81448
|
-
last_failure_code = ?, last_failure_retryable = ?,
|
|
81449
|
-
consecutive_failures = CASE WHEN ? = 'available' THEN 0 ELSE consecutive_failures + 1 END,
|
|
81450
|
-
updated_at = datetime('now')
|
|
81451
|
-
WHERE id = ?
|
|
81452
|
-
`,
|
|
81453
|
-
args: [
|
|
81454
|
-
args.operationalStatus,
|
|
81455
|
-
now,
|
|
81456
|
-
args.operationalStatus,
|
|
81457
|
-
now,
|
|
81458
|
-
args.operationalStatus,
|
|
81459
|
-
now,
|
|
81460
|
-
args.failureCode ?? null,
|
|
81461
|
-
args.retryable == null ? null : args.retryable ? 1 : 0,
|
|
81462
|
-
args.operationalStatus,
|
|
81463
|
-
args.connectionId
|
|
81464
|
-
]
|
|
81465
|
-
});
|
|
81466
|
-
await getDb().execute({
|
|
81467
|
-
sql: `INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
81468
|
-
args: [(0, import_node_crypto59.randomUUID)(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
|
|
81469
|
-
});
|
|
81470
|
-
}
|
|
81471
|
-
async function setServiceConnectionActions(identity, connectionId, enabled) {
|
|
81472
|
-
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
81473
|
-
if (!connection || connection.lifecycleStatus === "disconnected") throw new Error("service_connection_not_found");
|
|
81474
|
-
await getDb().execute({
|
|
81475
|
-
sql: `UPDATE service_connections SET actions_enabled = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
81476
|
-
args: [enabled ? 1 : 0, connectionId, connection.userId]
|
|
81477
|
-
});
|
|
81478
|
-
return enabled;
|
|
81479
|
-
}
|
|
81480
|
-
async function markServiceConnectionDisconnected(identity, connectionId) {
|
|
81481
|
-
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
81482
|
-
if (!connection) throw new Error("service_connection_not_found");
|
|
81483
|
-
await getDb().execute({
|
|
81484
|
-
sql: `UPDATE service_connections SET lifecycle_status = 'disconnected', operational_status = 'unknown', reconnect_required = 0, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
81485
|
-
args: [connectionId, connection.userId]
|
|
81486
|
-
});
|
|
81487
|
-
const remaining = await getDb().execute({
|
|
81488
|
-
sql: `SELECT COUNT(*) AS count FROM service_connections WHERE user_id = ? AND transport = 'nango' AND lifecycle_status = 'connected'`,
|
|
81489
|
-
args: [connection.userId]
|
|
81490
|
-
});
|
|
81491
|
-
return Number(remaining.rows[0]?.count ?? 0);
|
|
81492
|
-
}
|
|
81493
|
-
async function recordServiceConnectionAction(args) {
|
|
81494
|
-
await ensureServiceConnectionsSchema();
|
|
81495
|
-
const connection = await getOwnedServiceConnection(args.identity, args.connectionId);
|
|
81496
|
-
if (!connection) throw new Error("service_connection_not_found");
|
|
81497
|
-
await getDb().execute({
|
|
81498
|
-
sql: `UPDATE service_connection_action_audit SET status = ?, error_code = ?, result_json = ? WHERE user_id = ? AND request_id = ? AND connection_id = ?`,
|
|
81499
|
-
args: [args.status, args.errorCode ?? null, args.result === void 0 ? null : JSON.stringify(args.result), connection.userId, args.requestId, connection.id]
|
|
81500
|
-
});
|
|
81501
|
-
}
|
|
81502
|
-
async function claimServiceConnectionAction(args) {
|
|
81503
|
-
await ensureServiceConnectionsSchema();
|
|
81504
|
-
const connection = await getOwnedServiceConnection(args.identity, args.connectionId);
|
|
81505
|
-
if (!connection) throw new Error("service_connection_not_found");
|
|
81506
|
-
const inserted = await getDb().execute({
|
|
81507
|
-
sql: `INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)`,
|
|
81508
|
-
args: [(0, import_node_crypto59.randomUUID)(), connection.id, connection.userId, args.tool, args.requestId, args.requestDigest]
|
|
81509
|
-
});
|
|
81510
|
-
if (Number(inserted.rowsAffected ?? 0) === 1) return { claimed: true };
|
|
81511
|
-
const existing = await getDb().execute({
|
|
81512
|
-
sql: `SELECT connection_id, tool, status, error_code, request_digest, result_json FROM service_connection_action_audit WHERE user_id = ? AND request_id = ? LIMIT 1`,
|
|
81513
|
-
args: [connection.userId, args.requestId]
|
|
81514
|
-
});
|
|
81515
|
-
const row = existing.rows[0];
|
|
81516
|
-
const conflict = String(row?.connection_id ?? "") !== connection.id || String(row?.tool ?? "") !== args.tool || String(row?.request_digest ?? "") !== args.requestDigest;
|
|
81517
|
-
let result = void 0;
|
|
81518
|
-
if (!conflict && typeof row?.result_json === "string") {
|
|
81519
|
-
try {
|
|
81520
|
-
result = JSON.parse(row.result_json);
|
|
81521
|
-
} catch {
|
|
81522
|
-
result = void 0;
|
|
81523
|
-
}
|
|
81524
|
-
}
|
|
81525
|
-
return {
|
|
81526
|
-
claimed: false,
|
|
81527
|
-
status: String(row?.status ?? "unknown"),
|
|
81528
|
-
errorCode: typeof row?.error_code === "string" ? row.error_code : null,
|
|
81529
|
-
conflict,
|
|
81530
|
-
...result !== void 0 ? { result } : {}
|
|
81531
|
-
};
|
|
81532
|
-
}
|
|
81533
|
-
var import_node_crypto59, schemaReady3, schemaDb6;
|
|
81534
|
-
var init_service_connections = __esm({
|
|
81535
|
-
"src/api/service-connections.ts"() {
|
|
81536
|
-
"use strict";
|
|
81537
|
-
import_node_crypto59 = require("crypto");
|
|
81538
|
-
init_db();
|
|
81539
|
-
schemaReady3 = null;
|
|
81540
|
-
schemaDb6 = null;
|
|
81541
|
-
}
|
|
81542
|
-
});
|
|
81543
|
-
|
|
81544
81837
|
// src/api/scheduler-integration-auth.ts
|
|
81545
81838
|
function signingSecret() {
|
|
81546
81839
|
const secret2 = process.env.SCHEDULER_INTEGRATION_SIGNING_SECRET?.trim();
|
|
@@ -84444,6 +84737,15 @@ function retryAfterMsFromText(value) {
|
|
|
84444
84737
|
function normalizeNangoClientError(error) {
|
|
84445
84738
|
if (error instanceof MainNangoTransportError) return error;
|
|
84446
84739
|
const detail = nangoClientErrorText(error);
|
|
84740
|
+
const structured = error && typeof error === "object" ? error : null;
|
|
84741
|
+
if (structured?.code === -32001 || structured?.name === "RequestTimeout" || /Request timed out|RequestTimeout|Maximum total timeout exceeded/i.test(detail)) {
|
|
84742
|
+
return new MainNangoTransportError(
|
|
84743
|
+
"The connected service operation timed out before returning a result. Retry failed items or use a smaller batch.",
|
|
84744
|
+
503,
|
|
84745
|
+
"mcp_request_timeout",
|
|
84746
|
+
true
|
|
84747
|
+
);
|
|
84748
|
+
}
|
|
84447
84749
|
if (/SERVICE_DISABLED|accessNotConfigured/i.test(detail)) {
|
|
84448
84750
|
return new MainNangoTransportError(
|
|
84449
84751
|
"The provider API required by this connection is disabled. Enable it in the provider project, wait for propagation, then retry.",
|
|
@@ -84474,6 +84776,12 @@ function normalizeNangoClientError(error) {
|
|
|
84474
84776
|
}
|
|
84475
84777
|
return new MainNangoTransportError("The service connection is temporarily unavailable.", 503, "connection_transport_unavailable");
|
|
84476
84778
|
}
|
|
84779
|
+
async function callNangoToolWithBudget(client2, tool, input) {
|
|
84780
|
+
return client2.callTool(
|
|
84781
|
+
{ name: tool, arguments: input },
|
|
84782
|
+
{ timeout: NANGO_TOOL_CALL_TIMEOUT_MS }
|
|
84783
|
+
);
|
|
84784
|
+
}
|
|
84477
84785
|
function asRecord2(value) {
|
|
84478
84786
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
84479
84787
|
}
|
|
@@ -84917,7 +85225,7 @@ async function callNangoToolDirect(args) {
|
|
|
84917
85225
|
let result;
|
|
84918
85226
|
let providerError;
|
|
84919
85227
|
try {
|
|
84920
|
-
result = await withNangoClient(connection, (client2) => client2
|
|
85228
|
+
result = await withNangoClient(connection, (client2) => callNangoToolWithBudget(client2, args.tool, args.input));
|
|
84921
85229
|
} catch (error) {
|
|
84922
85230
|
providerError = error;
|
|
84923
85231
|
}
|
|
@@ -84982,7 +85290,7 @@ async function describeNangoToolDirect(identity, connectionId, toolName) {
|
|
|
84982
85290
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
84983
85291
|
};
|
|
84984
85292
|
}
|
|
84985
|
-
var import_node_crypto68, import_client13, DEFAULT_NANGO_MCP_URL, NANGO_TIMEOUT_MS, NANGO_CONNECTION_PAGE_SIZE, NANGO_CONNECTION_MAX_PAGES, PROVIDER_IDENTITY_RETRY_MS, MAIN_INTEGRATION_CONTRACT_VERSION, MAIN_INTEGRATION_CONTRACT_HASH, MainNangoTransportError, IDENTITY_SUPPORTED_PROVIDERS;
|
|
85293
|
+
var import_node_crypto68, import_client13, DEFAULT_NANGO_MCP_URL, NANGO_TIMEOUT_MS, NANGO_TOOL_CALL_TIMEOUT_MS, NANGO_CONNECTION_PAGE_SIZE, NANGO_CONNECTION_MAX_PAGES, PROVIDER_IDENTITY_RETRY_MS, MAIN_INTEGRATION_CONTRACT_VERSION, MAIN_INTEGRATION_CONTRACT_HASH, MainNangoTransportError, IDENTITY_SUPPORTED_PROVIDERS;
|
|
84986
85294
|
var init_main_nango_transport = __esm({
|
|
84987
85295
|
"src/api/main-nango-transport.ts"() {
|
|
84988
85296
|
"use strict";
|
|
@@ -84994,6 +85302,7 @@ var init_main_nango_transport = __esm({
|
|
|
84994
85302
|
init_connected_tool_policy();
|
|
84995
85303
|
DEFAULT_NANGO_MCP_URL = "https://api.nango.dev/mcp";
|
|
84996
85304
|
NANGO_TIMEOUT_MS = 2e4;
|
|
85305
|
+
NANGO_TOOL_CALL_TIMEOUT_MS = 24e4;
|
|
84997
85306
|
NANGO_CONNECTION_PAGE_SIZE = 100;
|
|
84998
85307
|
NANGO_CONNECTION_MAX_PAGES = 20;
|
|
84999
85308
|
PROVIDER_IDENTITY_RETRY_MS = 6 * 60 * 60 * 1e3;
|