mcp-scraper 0.66.6 → 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 +9 -1
- package/README.md +1 -1
- package/dist/bin/api-server.cjs +889 -597
- 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 +102 -16
- 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-NLEAYKOC.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-KPE52NPT.js → chunk-O7ZC5Y3Z.js} +1 -1
- package/dist/{chunk-3TKKJQB4.js → chunk-U2UHJWFW.js} +1 -1
- package/dist/{chunk-VMWVEKZT.js → chunk-Z5QQEWXA.js} +50 -17
- 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-5WPS3LZD.js → server-KSVJ4X4V.js} +633 -444
- 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();
|
|
@@ -56655,11 +57189,11 @@ function analyticsReportPath(input, report) {
|
|
|
56655
57189
|
const suffix2 = query.size ? `?${query.toString()}` : "";
|
|
56656
57190
|
return `/analytics/sites/${encodeURIComponent(input.siteId)}/${report}${suffix2}`;
|
|
56657
57191
|
}
|
|
56658
|
-
var
|
|
57192
|
+
var import_node_crypto36, HttpMcpToolExecutor;
|
|
56659
57193
|
var init_http_mcp_tool_executor = __esm({
|
|
56660
57194
|
"src/mcp/http-mcp-tool-executor.ts"() {
|
|
56661
57195
|
"use strict";
|
|
56662
|
-
|
|
57196
|
+
import_node_crypto36 = require("crypto");
|
|
56663
57197
|
init_harvest_timeout();
|
|
56664
57198
|
init_browser_service_env();
|
|
56665
57199
|
init_errors();
|
|
@@ -56728,13 +57262,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
56728
57262
|
});
|
|
56729
57263
|
}
|
|
56730
57264
|
async callDirectoryWorkflowStart(body, explicitIdempotencyKey) {
|
|
56731
|
-
const idempotencyKey4 = `mcp-directory-${(0,
|
|
57265
|
+
const idempotencyKey4 = `mcp-directory-${(0, import_node_crypto36.createHash)("sha256").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56732
57266
|
return this.call("/directory/run", body, this.timeoutMs, "POST", {
|
|
56733
57267
|
"Idempotency-Key": idempotencyKey4
|
|
56734
57268
|
});
|
|
56735
57269
|
}
|
|
56736
57270
|
async callSiteExtractStart(toolName, body, explicitIdempotencyKey) {
|
|
56737
|
-
const idempotencyKey4 = `mcp-site-${(0,
|
|
57271
|
+
const idempotencyKey4 = `mcp-site-${(0, import_node_crypto36.createHash)("sha256").update(toolName).update("\0").update(explicitIdempotencyKey).digest("hex")}`;
|
|
56738
57272
|
return this.call("/extract-site", body, this.timeoutMs, "POST", {
|
|
56739
57273
|
"Idempotency-Key": idempotencyKey4
|
|
56740
57274
|
});
|
|
@@ -57178,7 +57712,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57178
57712
|
report: input.report,
|
|
57179
57713
|
format: input.format
|
|
57180
57714
|
}, this.timeoutMs, "POST", {
|
|
57181
|
-
"Idempotency-Key": `analytics-export-${(0,
|
|
57715
|
+
"Idempotency-Key": `analytics-export-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57182
57716
|
});
|
|
57183
57717
|
}
|
|
57184
57718
|
commonsSearchEntities(input) {
|
|
@@ -57217,7 +57751,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57217
57751
|
commonsSubmitEntity(input) {
|
|
57218
57752
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57219
57753
|
return this.call("/commons/entities/propose", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57220
|
-
"Idempotency-Key": `commons-${(0,
|
|
57754
|
+
"Idempotency-Key": `commons-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57221
57755
|
});
|
|
57222
57756
|
}
|
|
57223
57757
|
commonsGetEntityLedger(input) {
|
|
@@ -57232,7 +57766,7 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57232
57766
|
commonsUpdateEditorialArticle(input) {
|
|
57233
57767
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57234
57768
|
return this.call("/commons/publications/articles", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57235
|
-
"Idempotency-Key": `commons-article-${(0,
|
|
57769
|
+
"Idempotency-Key": `commons-article-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57236
57770
|
});
|
|
57237
57771
|
}
|
|
57238
57772
|
commonsSaveFilter(input) {
|
|
@@ -57253,13 +57787,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57253
57787
|
commonsClaimPublication(input) {
|
|
57254
57788
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57255
57789
|
return this.call("/commons/publications/claim", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57256
|
-
"Idempotency-Key": `commons-publication-claim-${(0,
|
|
57790
|
+
"Idempotency-Key": `commons-publication-claim-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57257
57791
|
});
|
|
57258
57792
|
}
|
|
57259
57793
|
commonsPublishEditorial(input) {
|
|
57260
57794
|
const { idempotencyKey: idempotencyKey4, ...body } = input;
|
|
57261
57795
|
return this.call("/commons/publications/publish", { ...body, idempotencyKey: idempotencyKey4 }, this.timeoutMs, "POST", {
|
|
57262
|
-
"Idempotency-Key": `commons-publication-publish-${(0,
|
|
57796
|
+
"Idempotency-Key": `commons-publication-publish-${(0, import_node_crypto36.createHash)("sha256").update(idempotencyKey4).digest("hex")}`
|
|
57263
57797
|
});
|
|
57264
57798
|
}
|
|
57265
57799
|
commonsGetPublication(input) {
|
|
@@ -57267,13 +57801,13 @@ var init_http_mcp_tool_executor = __esm({
|
|
|
57267
57801
|
return this.getJson(input.subdomain ? `/commons/publications/${encodeURIComponent(input.subdomain)}?${query}` : `/commons/publications/me?${query}`);
|
|
57268
57802
|
}
|
|
57269
57803
|
async captureSerpSnapshot(input) {
|
|
57270
|
-
const fingerprint2 = (0,
|
|
57804
|
+
const fingerprint2 = (0, import_node_crypto36.createHash)("sha256").update(JSON.stringify(input)).digest("hex");
|
|
57271
57805
|
const now = Date.now();
|
|
57272
57806
|
for (const [pendingFingerprint, pendingEntry] of this.pendingSerpCaptureBillingKeys) {
|
|
57273
57807
|
if (pendingEntry.expiresAt <= now) this.pendingSerpCaptureBillingKeys.delete(pendingFingerprint);
|
|
57274
57808
|
}
|
|
57275
57809
|
const pending = this.pendingSerpCaptureBillingKeys.get(fingerprint2);
|
|
57276
|
-
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0,
|
|
57810
|
+
const idempotencyKey4 = pending && pending.expiresAt > now ? pending.key : (0, import_node_crypto36.randomUUID)();
|
|
57277
57811
|
this.pendingSerpCaptureBillingKeys.set(fingerprint2, {
|
|
57278
57812
|
key: idempotencyKey4,
|
|
57279
57813
|
expiresAt: now + 15 * 6e4
|
|
@@ -63283,7 +63817,7 @@ async function createImageSourceArtifact(args) {
|
|
|
63283
63817
|
if (args.content.length === 0 || args.content.length > IMAGE_SOURCE_MAX_BYTES) {
|
|
63284
63818
|
throw new Error("image_source_size_invalid");
|
|
63285
63819
|
}
|
|
63286
|
-
const id = (0,
|
|
63820
|
+
const id = (0, import_node_crypto37.randomUUID)().replaceAll("-", "");
|
|
63287
63821
|
return createPrivateArtifact({
|
|
63288
63822
|
policy: policy4(),
|
|
63289
63823
|
ownerId: args.ownerId,
|
|
@@ -63302,11 +63836,11 @@ async function readOwnedImageSourceArtifact(args) {
|
|
|
63302
63836
|
maxBytes: IMAGE_SOURCE_MAX_BYTES
|
|
63303
63837
|
});
|
|
63304
63838
|
}
|
|
63305
|
-
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;
|
|
63306
63840
|
var init_image_source_artifacts = __esm({
|
|
63307
63841
|
"src/api/image-source-artifacts.ts"() {
|
|
63308
63842
|
"use strict";
|
|
63309
|
-
|
|
63843
|
+
import_node_crypto37 = require("crypto");
|
|
63310
63844
|
init_private_artifacts();
|
|
63311
63845
|
IMAGE_SOURCE_ARTIFACT_PREFIX = "image-sources/";
|
|
63312
63846
|
IMAGE_SOURCE_ARTIFACT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -64920,7 +65454,7 @@ async function runBrowserAgentMigration() {
|
|
|
64920
65454
|
}
|
|
64921
65455
|
async function createExtensionRow(input) {
|
|
64922
65456
|
const db = getDb();
|
|
64923
|
-
const id = `bext_${(0,
|
|
65457
|
+
const id = `bext_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
64924
65458
|
await db.execute({
|
|
64925
65459
|
sql: `INSERT INTO browser_agent_extensions (id, user_id, name, backend_id, backend_name, source, source_url, size_bytes)
|
|
64926
65460
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -64955,7 +65489,7 @@ async function deleteExtensionRow(userId, name) {
|
|
|
64955
65489
|
}
|
|
64956
65490
|
async function createAuthConnectionRow(input) {
|
|
64957
65491
|
const db = getDb();
|
|
64958
|
-
const connectionId = `authc_${(0,
|
|
65492
|
+
const connectionId = `authc_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
64959
65493
|
await db.execute({
|
|
64960
65494
|
sql: `INSERT INTO browser_auth_connections (connection_id, domain, profile, account_email, note, status, browser_agent_session_id)
|
|
64961
65495
|
VALUES (?, ?, ?, ?, ?, 'NEEDS_AUTH', ?)`,
|
|
@@ -65040,7 +65574,7 @@ async function deleteProfileLabel(userId, profile) {
|
|
|
65040
65574
|
}
|
|
65041
65575
|
async function createSessionRow(input) {
|
|
65042
65576
|
const db = getDb();
|
|
65043
|
-
const id = `bas_${(0,
|
|
65577
|
+
const id = `bas_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
65044
65578
|
await db.execute({
|
|
65045
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)
|
|
65046
65580
|
VALUES (?, ?, ?, ?, 'open', ?, ?, ?, datetime('now'))`,
|
|
@@ -65117,7 +65651,7 @@ async function recordAction(input) {
|
|
|
65117
65651
|
sql: `INSERT INTO browser_agent_actions (id, session_id, type, params_json, ok, error)
|
|
65118
65652
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
65119
65653
|
args: [
|
|
65120
|
-
`baa_${(0,
|
|
65654
|
+
`baa_${(0, import_node_crypto38.randomUUID)().replace(/-/g, "").slice(0, 20)}`,
|
|
65121
65655
|
input.sessionId,
|
|
65122
65656
|
input.type,
|
|
65123
65657
|
input.params == null ? null : JSON.stringify(input.params),
|
|
@@ -65157,11 +65691,11 @@ async function listReplayRows(sessionId) {
|
|
|
65157
65691
|
});
|
|
65158
65692
|
return res.rows;
|
|
65159
65693
|
}
|
|
65160
|
-
var
|
|
65694
|
+
var import_node_crypto38, _ready2, _migrationPromise2, ORPHANED_SESSION_STATUS;
|
|
65161
65695
|
var init_browser_agent_db = __esm({
|
|
65162
65696
|
"src/api/browser-agent-db.ts"() {
|
|
65163
65697
|
"use strict";
|
|
65164
|
-
|
|
65698
|
+
import_node_crypto38 = require("crypto");
|
|
65165
65699
|
init_db();
|
|
65166
65700
|
_ready2 = false;
|
|
65167
65701
|
_migrationPromise2 = null;
|
|
@@ -66303,7 +66837,7 @@ var init_browser_agent_service = __esm({
|
|
|
66303
66837
|
|
|
66304
66838
|
// src/api/serp-identity-db.ts
|
|
66305
66839
|
async function createSerpIdentityRow(input) {
|
|
66306
|
-
const id = `serpi_${(0,
|
|
66840
|
+
const id = `serpi_${(0, import_node_crypto39.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
|
|
66307
66841
|
await getDb().execute({
|
|
66308
66842
|
sql: `INSERT INTO serp_identities
|
|
66309
66843
|
(id, user_id, name, kernel_profile_name, kernel_proxy_id, proxy_type, country, status)
|
|
@@ -66348,11 +66882,11 @@ async function deleteSerpIdentityRow(userId, name) {
|
|
|
66348
66882
|
args: [userId, name]
|
|
66349
66883
|
});
|
|
66350
66884
|
}
|
|
66351
|
-
var
|
|
66885
|
+
var import_node_crypto39;
|
|
66352
66886
|
var init_serp_identity_db = __esm({
|
|
66353
66887
|
"src/api/serp-identity-db.ts"() {
|
|
66354
66888
|
"use strict";
|
|
66355
|
-
|
|
66889
|
+
import_node_crypto39 = require("crypto");
|
|
66356
66890
|
init_db();
|
|
66357
66891
|
}
|
|
66358
66892
|
});
|
|
@@ -66364,8 +66898,8 @@ function kernelClient() {
|
|
|
66364
66898
|
return new import_sdk10.default({ apiKey });
|
|
66365
66899
|
}
|
|
66366
66900
|
function backendName(userId, name, resource) {
|
|
66367
|
-
const digest2 = (0,
|
|
66368
|
-
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);
|
|
66369
66903
|
return `mcp-serp-${resource}-${digest2}-${nonce}`;
|
|
66370
66904
|
}
|
|
66371
66905
|
function isNotFound2(error) {
|
|
@@ -66443,11 +66977,11 @@ async function deleteSerpIdentity(userId, name) {
|
|
|
66443
66977
|
throw error;
|
|
66444
66978
|
}
|
|
66445
66979
|
}
|
|
66446
|
-
var
|
|
66980
|
+
var import_node_crypto40, import_sdk10, MAX_SERP_IDENTITIES_PER_USER;
|
|
66447
66981
|
var init_serp_identity_service = __esm({
|
|
66448
66982
|
"src/api/serp-identity-service.ts"() {
|
|
66449
66983
|
"use strict";
|
|
66450
|
-
|
|
66984
|
+
import_node_crypto40 = require("crypto");
|
|
66451
66985
|
import_sdk10 = __toESM(require("@onkernel/sdk"), 1);
|
|
66452
66986
|
init_browser_service_env();
|
|
66453
66987
|
init_serp_identity_db();
|
|
@@ -67158,7 +67692,7 @@ function buildBrowserAgentRoutes() {
|
|
|
67158
67692
|
}
|
|
67159
67693
|
const existing = await getExtensionRow(user.id, name);
|
|
67160
67694
|
if (existing) return c.json({ error: `an extension named "${name}" already exists \u2014 delete it first or pick another name` }, 409);
|
|
67161
|
-
const backendName2 = `u${user.id}_${(0,
|
|
67695
|
+
const backendName2 = `u${user.id}_${(0, import_node_crypto41.randomUUID)().replace(/-/g, "")}`;
|
|
67162
67696
|
try {
|
|
67163
67697
|
const imported = await importExtensionFromStore(storeUrl, backendName2);
|
|
67164
67698
|
const row = await createExtensionRow({
|
|
@@ -67217,11 +67751,11 @@ function buildBrowserAgentRoutes() {
|
|
|
67217
67751
|
});
|
|
67218
67752
|
return app2;
|
|
67219
67753
|
}
|
|
67220
|
-
var
|
|
67754
|
+
var import_node_crypto41, import_hono24, auth, DEFAULT_BROWSER_SESSION_LOCK_TTL_SECONDS, EXTENSION_NAME_RE, SERP_IDENTITY_NAME_RE;
|
|
67221
67755
|
var init_browser_agent_routes = __esm({
|
|
67222
67756
|
"src/api/browser-agent-routes.ts"() {
|
|
67223
67757
|
"use strict";
|
|
67224
|
-
|
|
67758
|
+
import_node_crypto41 = require("crypto");
|
|
67225
67759
|
import_hono24 = require("hono");
|
|
67226
67760
|
init_api_auth();
|
|
67227
67761
|
init_errors();
|
|
@@ -67779,7 +68313,7 @@ async function getKeys() {
|
|
|
67779
68313
|
const privateKey = await (0, import_jose2.importPKCS8)(pem, "RS256", { extractable: true });
|
|
67780
68314
|
const full = await (0, import_jose2.exportJWK)(privateKey);
|
|
67781
68315
|
const publicJwk = { kty: full.kty, n: full.n, e: full.e };
|
|
67782
|
-
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);
|
|
67783
68317
|
publicJwk.kid = kid;
|
|
67784
68318
|
publicJwk.alg = "RS256";
|
|
67785
68319
|
publicJwk.use = "sig";
|
|
@@ -67958,23 +68492,23 @@ async function validateAuthRequest(p) {
|
|
|
67958
68492
|
}
|
|
67959
68493
|
function pkceMatches(verifier, challenge) {
|
|
67960
68494
|
if (!verifier) return false;
|
|
67961
|
-
const computed = (0,
|
|
68495
|
+
const computed = (0, import_node_crypto42.createHash)("sha256").update(verifier).digest("base64url");
|
|
67962
68496
|
return computed === challenge;
|
|
67963
68497
|
}
|
|
67964
68498
|
async function mintAccessToken(identity, scope, plan, audience) {
|
|
67965
68499
|
const { privateKey, kid } = await getKeys();
|
|
67966
|
-
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);
|
|
67967
68501
|
}
|
|
67968
68502
|
function tokenErrorResponse(c, error, description, status) {
|
|
67969
68503
|
return c.json({ error, error_description: description }, status);
|
|
67970
68504
|
}
|
|
67971
|
-
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;
|
|
67972
68506
|
var init_oauth_routes = __esm({
|
|
67973
68507
|
"src/api/oauth-routes.ts"() {
|
|
67974
68508
|
"use strict";
|
|
67975
68509
|
import_hono26 = require("hono");
|
|
67976
68510
|
import_cookie = require("hono/cookie");
|
|
67977
|
-
|
|
68511
|
+
import_node_crypto42 = require("crypto");
|
|
67978
68512
|
import_jose2 = require("jose");
|
|
67979
68513
|
init_session();
|
|
67980
68514
|
init_db();
|
|
@@ -68081,7 +68615,7 @@ var init_oauth_routes = __esm({
|
|
|
68081
68615
|
}
|
|
68082
68616
|
}
|
|
68083
68617
|
const clientName = typeof body.client_name === "string" ? body.client_name : null;
|
|
68084
|
-
const clientId = `client_${(0,
|
|
68618
|
+
const clientId = `client_${(0, import_node_crypto42.randomBytes)(16).toString("hex")}`;
|
|
68085
68619
|
await withOAuthDatabaseDeadline("register-client", registerClient(clientId, redirectUris, clientName));
|
|
68086
68620
|
console.log("[oauth-dcr] register OK client_id=%s redirect_uris=%s", clientId, JSON.stringify(redirectUris));
|
|
68087
68621
|
return c.json({
|
|
@@ -68134,7 +68668,7 @@ var init_oauth_routes = __esm({
|
|
|
68134
68668
|
if (action3 === "deny") return redirectWithError(p.redirect_uri, p.state, "access_denied");
|
|
68135
68669
|
if (action3 !== "approve") return c.text("unsupported action", 400);
|
|
68136
68670
|
const scope = negotiateScope(p.scope, user, p.resource);
|
|
68137
|
-
const code = `code_${(0,
|
|
68671
|
+
const code = `code_${(0, import_node_crypto42.randomBytes)(32).toString("base64url")}`;
|
|
68138
68672
|
const expiresAt = new Date(Date.now() + CODE_TTL_SECONDS * 1e3).toISOString();
|
|
68139
68673
|
await withOAuthDatabaseDeadline("put-authorization-code", putCode({
|
|
68140
68674
|
code,
|
|
@@ -68173,7 +68707,7 @@ var init_oauth_routes = __esm({
|
|
|
68173
68707
|
const plan = user ? resolvePlan(user) : "free";
|
|
68174
68708
|
const audience = record.resource ?? RESOURCE();
|
|
68175
68709
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
68176
|
-
const refreshToken = `rt_${(0,
|
|
68710
|
+
const refreshToken = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
68177
68711
|
await withOAuthDatabaseDeadline("put-refresh-token", putRefresh({
|
|
68178
68712
|
refresh_token: refreshToken,
|
|
68179
68713
|
client_id: clientId,
|
|
@@ -68203,7 +68737,7 @@ var init_oauth_routes = __esm({
|
|
|
68203
68737
|
const plan = user ? resolvePlan(user) : "free";
|
|
68204
68738
|
const audience = record.resource ?? RESOURCE();
|
|
68205
68739
|
const accessToken = await mintAccessToken(record.identity, record.scope, plan, audience);
|
|
68206
|
-
const nextRefresh = `rt_${(0,
|
|
68740
|
+
const nextRefresh = `rt_${(0, import_node_crypto42.randomBytes)(40).toString("base64url")}`;
|
|
68207
68741
|
await withOAuthDatabaseDeadline("rotate-refresh-token", rotateRefresh(refreshToken, {
|
|
68208
68742
|
refresh_token: nextRefresh,
|
|
68209
68743
|
client_id: record.client_id,
|
|
@@ -69623,7 +70157,7 @@ function quoteUntrusted(value) {
|
|
|
69623
70157
|
return clean3.split("\n").map((line) => `> ${line}`).join("\n");
|
|
69624
70158
|
}
|
|
69625
70159
|
function shortHash(value, length = 24) {
|
|
69626
|
-
return (0,
|
|
70160
|
+
return (0, import_node_crypto43.createHash)("sha256").update(value).digest("hex").slice(0, length);
|
|
69627
70161
|
}
|
|
69628
70162
|
function safePathPart(value) {
|
|
69629
70163
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "contact";
|
|
@@ -70111,11 +70645,11 @@ async function captureSupportMessage(memoryKey, email, options) {
|
|
|
70111
70645
|
direction: options.direction
|
|
70112
70646
|
};
|
|
70113
70647
|
}
|
|
70114
|
-
var
|
|
70648
|
+
var import_node_crypto43, SUPPORT_TAGS, ISSUE_TAGS;
|
|
70115
70649
|
var init_resend_support_thread = __esm({
|
|
70116
70650
|
"src/api/resend-support-thread.ts"() {
|
|
70117
70651
|
"use strict";
|
|
70118
|
-
|
|
70652
|
+
import_node_crypto43 = require("crypto");
|
|
70119
70653
|
init_memory();
|
|
70120
70654
|
SUPPORT_TAGS = [
|
|
70121
70655
|
{
|
|
@@ -70700,7 +71234,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
70700
71234
|
) < ?
|
|
70701
71235
|
`,
|
|
70702
71236
|
args: [
|
|
70703
|
-
(0,
|
|
71237
|
+
(0, import_node_crypto44.randomUUID)(),
|
|
70704
71238
|
input.eventSlug,
|
|
70705
71239
|
input.email,
|
|
70706
71240
|
input.firstName,
|
|
@@ -70717,7 +71251,7 @@ async function claimWorkshopRegistration(input) {
|
|
|
70717
71251
|
id, event_slug, email, first_name, last_name, status
|
|
70718
71252
|
) VALUES (?, ?, ?, ?, ?, 'waitlisted')
|
|
70719
71253
|
`,
|
|
70720
|
-
args: [(0,
|
|
71254
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
70721
71255
|
});
|
|
70722
71256
|
const waitlisted = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
70723
71257
|
if (!waitlisted) throw new Error("workshop registration could not be claimed");
|
|
@@ -70732,7 +71266,7 @@ async function registerWorkshopInterest(input) {
|
|
|
70732
71266
|
id, event_slug, email, first_name, last_name, status
|
|
70733
71267
|
) VALUES (?, ?, ?, ?, ?, 'interested')
|
|
70734
71268
|
`,
|
|
70735
|
-
args: [(0,
|
|
71269
|
+
args: [(0, import_node_crypto44.randomUUID)(), input.eventSlug, input.email, input.firstName, input.lastName || null]
|
|
70736
71270
|
});
|
|
70737
71271
|
const registration = await getWorkshopRegistration(input.eventSlug, input.email);
|
|
70738
71272
|
if (!registration) throw new Error("workshop interest could not be recorded");
|
|
@@ -70762,11 +71296,11 @@ async function updateWorkshopRegistration(id, patch) {
|
|
|
70762
71296
|
args: [...entries.map(([, value]) => value), id]
|
|
70763
71297
|
});
|
|
70764
71298
|
}
|
|
70765
|
-
var
|
|
71299
|
+
var import_node_crypto44;
|
|
70766
71300
|
var init_workshop_registration_repository = __esm({
|
|
70767
71301
|
"src/api/workshop-registration-repository.ts"() {
|
|
70768
71302
|
"use strict";
|
|
70769
|
-
|
|
71303
|
+
import_node_crypto44 = require("crypto");
|
|
70770
71304
|
init_db();
|
|
70771
71305
|
}
|
|
70772
71306
|
});
|
|
@@ -71339,7 +71873,7 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
|
71339
71873
|
articleCount: articles.length,
|
|
71340
71874
|
wordCount: totalWordCount,
|
|
71341
71875
|
bytes,
|
|
71342
|
-
sha256: (0,
|
|
71876
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex"),
|
|
71343
71877
|
warnings
|
|
71344
71878
|
};
|
|
71345
71879
|
}
|
|
@@ -71422,14 +71956,14 @@ ${provenance}`;
|
|
|
71422
71956
|
...rendered,
|
|
71423
71957
|
html,
|
|
71424
71958
|
bytes: Buffer.byteLength(html),
|
|
71425
|
-
sha256: (0,
|
|
71959
|
+
sha256: (0, import_node_crypto45.createHash)("sha256").update(html).digest("hex")
|
|
71426
71960
|
};
|
|
71427
71961
|
}
|
|
71428
|
-
var
|
|
71962
|
+
var import_node_crypto45, import_node_fs14, import_node_path21, import_marked, runtimeEntryDir, assetCache;
|
|
71429
71963
|
var init_render = __esm({
|
|
71430
71964
|
"src/editorial-reading-room/render.ts"() {
|
|
71431
71965
|
"use strict";
|
|
71432
|
-
|
|
71966
|
+
import_node_crypto45 = require("crypto");
|
|
71433
71967
|
import_node_fs14 = require("fs");
|
|
71434
71968
|
import_node_path21 = require("path");
|
|
71435
71969
|
import_marked = require("marked");
|
|
@@ -71573,8 +72107,9 @@ var init_editorial_reading_room_routes = __esm({
|
|
|
71573
72107
|
|
|
71574
72108
|
// src/api/commons-image-store.ts
|
|
71575
72109
|
async function ensureCommonsImageSchema() {
|
|
71576
|
-
|
|
71577
|
-
|
|
72110
|
+
const db = getDb();
|
|
72111
|
+
if (imageSchemaReady && imageSchemaDb === db) return;
|
|
72112
|
+
await db.execute(`
|
|
71578
72113
|
CREATE TABLE IF NOT EXISTS commons_images (
|
|
71579
72114
|
id TEXT PRIMARY KEY,
|
|
71580
72115
|
user_id INTEGER NOT NULL,
|
|
@@ -71590,8 +72125,9 @@ async function ensureCommonsImageSchema() {
|
|
|
71590
72125
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
71591
72126
|
)
|
|
71592
72127
|
`);
|
|
71593
|
-
await
|
|
72128
|
+
await db.execute(`CREATE UNIQUE INDEX IF NOT EXISTS commons_images_digest ON commons_images(digest)`);
|
|
71594
72129
|
imageSchemaReady = true;
|
|
72130
|
+
imageSchemaDb = db;
|
|
71595
72131
|
}
|
|
71596
72132
|
function sniffImageFormat(bytes) {
|
|
71597
72133
|
if (bytes.length < 12) return null;
|
|
@@ -71621,7 +72157,7 @@ async function assertPublicHttpsUrl(rawUrl) {
|
|
|
71621
72157
|
try {
|
|
71622
72158
|
url = new URL(rawUrl);
|
|
71623
72159
|
} catch {
|
|
71624
|
-
throw new CommonsImageError("image_url_invalid",
|
|
72160
|
+
throw new CommonsImageError("image_url_invalid", "The image source is not a valid URL.");
|
|
71625
72161
|
}
|
|
71626
72162
|
if (url.protocol !== "https:") {
|
|
71627
72163
|
throw new CommonsImageError("image_url_not_https", "Commons image sources must be https URLs.");
|
|
@@ -71629,7 +72165,7 @@ async function assertPublicHttpsUrl(rawUrl) {
|
|
|
71629
72165
|
const hostname = url.hostname.replace(/^\[|\]$/g, "");
|
|
71630
72166
|
const addresses = (0, import_node_net2.isIP)(hostname) ? [{ address: hostname }] : await (0, import_promises16.lookup)(hostname, { all: true }).catch(() => []);
|
|
71631
72167
|
if (!addresses.length) {
|
|
71632
|
-
throw new CommonsImageError("image_host_unresolvable",
|
|
72168
|
+
throw new CommonsImageError("image_host_unresolvable", "The image source host could not be resolved.");
|
|
71633
72169
|
}
|
|
71634
72170
|
if (addresses.some((entry) => isBlockedAddress(entry.address))) {
|
|
71635
72171
|
throw new CommonsImageError("image_host_blocked", "Commons image sources cannot resolve to private or loopback addresses.");
|
|
@@ -71640,15 +72176,36 @@ async function downloadImage(sourceUrl) {
|
|
|
71640
72176
|
let current = sourceUrl;
|
|
71641
72177
|
for (let redirect = 0; redirect <= COMMONS_IMAGE_MAX_REDIRECTS; redirect += 1) {
|
|
71642
72178
|
const url = await assertPublicHttpsUrl(current);
|
|
71643
|
-
|
|
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
|
+
}
|
|
71644
72191
|
if (response.status >= 300 && response.status < 400) {
|
|
71645
72192
|
const location2 = response.headers.get("location");
|
|
71646
72193
|
if (!location2) throw new CommonsImageError("image_redirect_invalid", "Image source redirected without a destination.");
|
|
71647
|
-
|
|
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
|
+
}
|
|
71648
72199
|
continue;
|
|
71649
72200
|
}
|
|
71650
72201
|
if (!response.ok) {
|
|
71651
|
-
|
|
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
|
+
);
|
|
71652
72209
|
}
|
|
71653
72210
|
const declaredLength = Number(response.headers.get("content-length") ?? "0");
|
|
71654
72211
|
if (declaredLength > COMMONS_IMAGE_MAX_BYTES) {
|
|
@@ -71675,8 +72232,35 @@ function commonsImageBlobStore() {
|
|
|
71675
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();
|
|
71676
72233
|
return token6 ? new VercelBlobStore(token6) : getBlobStore();
|
|
71677
72234
|
}
|
|
71678
|
-
function
|
|
71679
|
-
|
|
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
|
+
};
|
|
71680
72264
|
}
|
|
71681
72265
|
async function hostCommonsImage(input) {
|
|
71682
72266
|
if (hostOverride) return hostOverride(input);
|
|
@@ -71693,7 +72277,7 @@ async function hostCommonsImage(input) {
|
|
|
71693
72277
|
415
|
|
71694
72278
|
);
|
|
71695
72279
|
}
|
|
71696
|
-
const digest2 = (0,
|
|
72280
|
+
const digest2 = (0, import_node_crypto46.createHash)("sha256").update(bytes).digest("hex");
|
|
71697
72281
|
const existing = await getDb().execute({
|
|
71698
72282
|
sql: "SELECT id, url, content_type, bytes, source_url FROM commons_images WHERE digest = ? LIMIT 1",
|
|
71699
72283
|
args: [digest2]
|
|
@@ -71747,7 +72331,8 @@ async function hostCommonsImage(input) {
|
|
|
71747
72331
|
async function hostEntityImages(input) {
|
|
71748
72332
|
const rewrite = { mediaUrls: /* @__PURE__ */ new Map(), dropped: [] };
|
|
71749
72333
|
const featuredUrl = input.featuredImage?.url;
|
|
71750
|
-
|
|
72334
|
+
const registeredFeatured = featuredUrl ? await findCommonsHostedImageByUrl(featuredUrl) : null;
|
|
72335
|
+
if (featuredUrl && !registeredFeatured) {
|
|
71751
72336
|
const hosted = await hostCommonsImage({
|
|
71752
72337
|
userId: input.userId,
|
|
71753
72338
|
sourceUrl: featuredUrl,
|
|
@@ -71755,17 +72340,19 @@ async function hostEntityImages(input) {
|
|
|
71755
72340
|
license: input.featuredImage?.license,
|
|
71756
72341
|
attribution: input.featuredImage?.sourceUrl
|
|
71757
72342
|
}).catch((error) => {
|
|
71758
|
-
|
|
72343
|
+
if (error instanceof CommonsImageError) throw error;
|
|
71759
72344
|
throw new CommonsImageError(
|
|
71760
|
-
|
|
71761
|
-
|
|
72345
|
+
"featured_image_unhostable",
|
|
72346
|
+
"The featured image could not be hosted, so the entity was not persisted with a link that could break.",
|
|
71762
72347
|
422
|
|
71763
72348
|
);
|
|
71764
72349
|
});
|
|
71765
72350
|
rewrite.featuredImageUrl = hosted.url;
|
|
72351
|
+
rewrite.mediaUrls.set(featuredUrl, hosted.url);
|
|
71766
72352
|
}
|
|
71767
72353
|
for (const item of input.media ?? []) {
|
|
71768
|
-
if (
|
|
72354
|
+
if (item.url && rewrite.mediaUrls.has(item.url)) continue;
|
|
72355
|
+
if (!item.url || await findCommonsHostedImageByUrl(item.url)) continue;
|
|
71769
72356
|
try {
|
|
71770
72357
|
const hosted = await hostCommonsImage({
|
|
71771
72358
|
userId: input.userId,
|
|
@@ -71781,11 +72368,11 @@ async function hostEntityImages(input) {
|
|
|
71781
72368
|
}
|
|
71782
72369
|
return rewrite;
|
|
71783
72370
|
}
|
|
71784
|
-
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;
|
|
71785
72372
|
var init_commons_image_store = __esm({
|
|
71786
72373
|
"src/api/commons-image-store.ts"() {
|
|
71787
72374
|
"use strict";
|
|
71788
|
-
|
|
72375
|
+
import_node_crypto46 = require("crypto");
|
|
71789
72376
|
import_promises16 = require("dns/promises");
|
|
71790
72377
|
import_node_net2 = require("net");
|
|
71791
72378
|
init_blob_store();
|
|
@@ -71793,17 +72380,23 @@ var init_commons_image_store = __esm({
|
|
|
71793
72380
|
COMMONS_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
71794
72381
|
COMMONS_IMAGE_MAX_REDIRECTS = 3;
|
|
71795
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.";
|
|
71796
72384
|
CommonsImageError = class extends Error {
|
|
71797
|
-
constructor(code, message, httpStatus = 400) {
|
|
72385
|
+
constructor(code, message, httpStatus = 400, retryable = false, retryGuidance = COMMONS_IMAGE_RETRY_GUIDANCE) {
|
|
71798
72386
|
super(message);
|
|
71799
72387
|
this.code = code;
|
|
71800
72388
|
this.httpStatus = httpStatus;
|
|
72389
|
+
this.retryable = retryable;
|
|
72390
|
+
this.retryGuidance = retryGuidance;
|
|
71801
72391
|
this.name = "CommonsImageError";
|
|
71802
72392
|
}
|
|
71803
72393
|
code;
|
|
71804
72394
|
httpStatus;
|
|
72395
|
+
retryable;
|
|
72396
|
+
retryGuidance;
|
|
71805
72397
|
};
|
|
71806
72398
|
imageSchemaReady = false;
|
|
72399
|
+
imageSchemaDb = null;
|
|
71807
72400
|
hostOverride = null;
|
|
71808
72401
|
}
|
|
71809
72402
|
});
|
|
@@ -71910,7 +72503,7 @@ function buildCommonsLinkset(entity, claims) {
|
|
|
71910
72503
|
context[claim.predicate] = targets;
|
|
71911
72504
|
}
|
|
71912
72505
|
const document2 = { linkset: [context] };
|
|
71913
|
-
const etag = `"${(0,
|
|
72506
|
+
const etag = `"${(0, import_node_crypto47.createHash)("sha256").update(JSON.stringify(document2)).digest("hex")}"`;
|
|
71914
72507
|
return { document: document2, etag, publicUrl, linksetUrl, profile: COMMONS_RELATIONSHIP_PROFILE };
|
|
71915
72508
|
}
|
|
71916
72509
|
function commonsLinksetDiscoveryHeader(idOrSlug) {
|
|
@@ -71978,11 +72571,11 @@ function normalizeHreflang(value) {
|
|
|
71978
72571
|
const languages = [...new Set(value.map((item) => optionalText(item, 80)).filter((item) => Boolean(item)))];
|
|
71979
72572
|
return languages.length ? languages : void 0;
|
|
71980
72573
|
}
|
|
71981
|
-
var
|
|
72574
|
+
var import_node_crypto47, COMMONS_LINKSET_MEDIA_TYPE, COMMONS_RELATIONSHIP_PROFILE, REGISTERED_RELATIONS;
|
|
71982
72575
|
var init_commons_linksets = __esm({
|
|
71983
72576
|
"src/api/commons-linksets.ts"() {
|
|
71984
72577
|
"use strict";
|
|
71985
|
-
|
|
72578
|
+
import_node_crypto47 = require("crypto");
|
|
71986
72579
|
COMMONS_LINKSET_MEDIA_TYPE = "application/linkset+json";
|
|
71987
72580
|
COMMONS_RELATIONSHIP_PROFILE = "https://mcpscraper.dev/commons/profiles/relationships/v1";
|
|
71988
72581
|
REGISTERED_RELATIONS = /* @__PURE__ */ new Set([
|
|
@@ -72025,9 +72618,9 @@ var init_commons_linksets = __esm({
|
|
|
72025
72618
|
|
|
72026
72619
|
// src/api/commons-repository.ts
|
|
72027
72620
|
async function ensureCommonsSchema() {
|
|
72028
|
-
if (
|
|
72621
|
+
if (schemaReady2) return;
|
|
72029
72622
|
if (await schemaObjectsPresent(COMMONS_SCHEMA_OBJECTS)) {
|
|
72030
|
-
|
|
72623
|
+
schemaReady2 = true;
|
|
72031
72624
|
return;
|
|
72032
72625
|
}
|
|
72033
72626
|
const db = getDb();
|
|
@@ -72250,7 +72843,7 @@ async function ensureCommonsSchema() {
|
|
|
72250
72843
|
args: [COMMONS_SCHEMA_VERSION]
|
|
72251
72844
|
}
|
|
72252
72845
|
], "write");
|
|
72253
|
-
|
|
72846
|
+
schemaReady2 = true;
|
|
72254
72847
|
}
|
|
72255
72848
|
async function searchCommonsEntities(filters = {}, userId) {
|
|
72256
72849
|
await ensureCommonsSchema();
|
|
@@ -72458,7 +73051,7 @@ async function prepareCommonsEntity(input, user) {
|
|
|
72458
73051
|
normalizedEntityType: entityType,
|
|
72459
73052
|
proposedSlug: slug4 || null,
|
|
72460
73053
|
publicUrl: slug4 ? publicUrlForSlug(slug4) : null,
|
|
72461
|
-
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"
|
|
72462
73055
|
},
|
|
72463
73056
|
contract,
|
|
72464
73057
|
billing: {
|
|
@@ -72480,8 +73073,8 @@ async function prepareCommonsEntity(input, user) {
|
|
|
72480
73073
|
"Search likely duplicates before submitting a new entity. If one matches, edit it with entityId and baseRevision instead of creating another page.",
|
|
72481
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.",
|
|
72482
73075
|
"Write neutral encyclopedia prose. Do not paste raw scrape Markdown, marketing layout fragments, or empty/filler headings.",
|
|
72483
|
-
"
|
|
72484
|
-
"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.",
|
|
72485
73078
|
"Validation is free. Submitting a new entity costs 10 Credits; submitting an edit to an existing entity costs 2 Credits."
|
|
72486
73079
|
]
|
|
72487
73080
|
};
|
|
@@ -72496,6 +73089,8 @@ async function validateCommonsEntity(input, user) {
|
|
|
72496
73089
|
const contract = commonsEntityProfileFor(input.entityType, input.seo?.schemaOrgType);
|
|
72497
73090
|
const source = normalizeSource(input.source);
|
|
72498
73091
|
const featuredImage = normalizeFeaturedImage(input.featuredImage);
|
|
73092
|
+
const normalizedFeaturedImageUrl = featuredImage?.url ? normalizeCommonsImageUrl(featuredImage.url) : null;
|
|
73093
|
+
const registeredFeaturedImage = normalizedFeaturedImageUrl ? await findCommonsHostedImageByUrl(normalizedFeaturedImageUrl) : null;
|
|
72499
73094
|
const bodyMarkdown = safeCandidateBody(input.bodyMarkdown, input.contentSections);
|
|
72500
73095
|
const headings = extractMarkdownHeadings(bodyMarkdown);
|
|
72501
73096
|
const placeholderSections = unsupportedPlaceholderSections(bodyMarkdown);
|
|
@@ -72533,15 +73128,44 @@ async function validateCommonsEntity(input, user) {
|
|
|
72533
73128
|
if (input.reviewPolicy === "always_review") {
|
|
72534
73129
|
warnings.push("reviewPolicy is always_review, so the proposal will not auto-publish even if the payload is otherwise valid.");
|
|
72535
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
|
+
}
|
|
72536
73134
|
if (user?.id == null) warnings.push("No authenticated user was supplied to validation; submit still requires API-key authenticated user context.");
|
|
72537
73135
|
const valid = errors.length === 0;
|
|
72538
|
-
const
|
|
73136
|
+
const imageReadyForPublish = Boolean(registeredFeaturedImage);
|
|
73137
|
+
const publishable = valid && imageReadyForPublish;
|
|
73138
|
+
const autoPublishEligible = publishable && input.reviewPolicy !== "always_review";
|
|
72539
73139
|
const tagVocabulary = await commonsTagVocabulary();
|
|
72540
73140
|
return {
|
|
72541
73141
|
ok: true,
|
|
72542
73142
|
valid,
|
|
72543
|
-
publishable
|
|
73143
|
+
publishable,
|
|
72544
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
|
+
},
|
|
72545
73169
|
errors,
|
|
72546
73170
|
warnings,
|
|
72547
73171
|
contract,
|
|
@@ -72622,7 +73246,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
72622
73246
|
const existingClaims = existing && normalized.claims !== void 0 ? await getCommonsClaimsByEntityId(existing.id) : [];
|
|
72623
73247
|
const safety = evaluatePublishSafety(normalized, existing);
|
|
72624
73248
|
const shouldApply = safety.safe && normalized.reviewPolicy !== "always_review";
|
|
72625
|
-
const proposalId = `commons-proposal-${(0,
|
|
73249
|
+
const proposalId = `commons-proposal-${(0, import_node_crypto48.randomUUID)()}`;
|
|
72626
73250
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
72627
73251
|
const entityId = existing?.id ?? normalized.entityId ?? allocateEntityId();
|
|
72628
73252
|
const proposalStatus = shouldApply ? "accepted" : "pending_review";
|
|
@@ -72677,7 +73301,7 @@ async function submitCommonsEntity(input, user) {
|
|
|
72677
73301
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
72678
73302
|
`,
|
|
72679
73303
|
args: [
|
|
72680
|
-
`commons-ledger-${(0,
|
|
73304
|
+
`commons-ledger-${(0, import_node_crypto48.randomUUID)()}`,
|
|
72681
73305
|
nextEntity.id,
|
|
72682
73306
|
proposalId,
|
|
72683
73307
|
user.id,
|
|
@@ -72783,7 +73407,7 @@ async function saveCommonsFilter(input, user) {
|
|
|
72783
73407
|
sql: "SELECT id FROM commons_saved_filters WHERE user_id = ? AND name = ? LIMIT 1",
|
|
72784
73408
|
args: [user.id, name]
|
|
72785
73409
|
});
|
|
72786
|
-
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)()}`;
|
|
72787
73411
|
await getDb().execute({
|
|
72788
73412
|
sql: `
|
|
72789
73413
|
INSERT INTO commons_saved_filters (id, user_id, name, description, filter_json, created_at, updated_at)
|
|
@@ -73561,7 +74185,7 @@ function commonsIndexDocuments(entity, now) {
|
|
|
73561
74185
|
return documents;
|
|
73562
74186
|
}
|
|
73563
74187
|
function commonsIndexDocumentId(entityId, documentType, documentKey) {
|
|
73564
|
-
return `commons-index-${(0,
|
|
74188
|
+
return `commons-index-${(0, import_node_crypto48.createHash)("sha256").update(`${entityId}
|
|
73565
74189
|
${documentType}
|
|
73566
74190
|
${documentKey}`).digest("hex").slice(0, 32)}`;
|
|
73567
74191
|
}
|
|
@@ -74127,11 +74751,11 @@ function jsonLikeValue(value) {
|
|
|
74127
74751
|
function escapeLike(value) {
|
|
74128
74752
|
return value.replace(/[%_]/g, "");
|
|
74129
74753
|
}
|
|
74130
|
-
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;
|
|
74131
74755
|
var init_commons_repository = __esm({
|
|
74132
74756
|
"src/api/commons-repository.ts"() {
|
|
74133
74757
|
"use strict";
|
|
74134
|
-
|
|
74758
|
+
import_node_crypto48 = require("crypto");
|
|
74135
74759
|
init_db();
|
|
74136
74760
|
init_commons_image_store();
|
|
74137
74761
|
init_commons_embeddings();
|
|
@@ -74286,7 +74910,7 @@ var init_commons_repository = __esm({
|
|
|
74286
74910
|
]
|
|
74287
74911
|
}
|
|
74288
74912
|
};
|
|
74289
|
-
|
|
74913
|
+
schemaReady2 = false;
|
|
74290
74914
|
COMMONS_SCHEMA_OBJECTS = [
|
|
74291
74915
|
"schema_migrations",
|
|
74292
74916
|
"commons_entities",
|
|
@@ -74510,7 +75134,7 @@ async function claimCommonsPublication(input, user) {
|
|
|
74510
75134
|
}
|
|
74511
75135
|
const existingName = await getCommonsPublicationBySubdomain(subdomain);
|
|
74512
75136
|
if (existingName) throw new CommonsPublicationError("publication_name_unavailable", "That publication name is already claimed.", 409);
|
|
74513
|
-
const id = `tcpub_${(0,
|
|
75137
|
+
const id = `tcpub_${(0, import_node_crypto49.randomUUID)()}`;
|
|
74514
75138
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
74515
75139
|
try {
|
|
74516
75140
|
await getDb().execute({
|
|
@@ -74562,7 +75186,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
74562
75186
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
74563
75187
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
74564
75188
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
74565
|
-
const editionId = `tced_${(0,
|
|
75189
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
74566
75190
|
const revision = (latest?.revision ?? 0) + 1;
|
|
74567
75191
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
74568
75192
|
await getDb().batch([
|
|
@@ -74586,7 +75210,7 @@ async function publishCommonsEditorial(input, user) {
|
|
|
74586
75210
|
JSON.stringify(editionInput.articles),
|
|
74587
75211
|
html,
|
|
74588
75212
|
rendered.filename,
|
|
74589
|
-
(0,
|
|
75213
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
74590
75214
|
rendered.articleCount,
|
|
74591
75215
|
rendered.wordCount,
|
|
74592
75216
|
Buffer.byteLength(html),
|
|
@@ -74644,7 +75268,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
74644
75268
|
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
74645
75269
|
const rendered = renderEditorialReadingRoom(editionInput);
|
|
74646
75270
|
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
74647
|
-
const editionId = `tced_${(0,
|
|
75271
|
+
const editionId = `tced_${(0, import_node_crypto49.randomUUID)()}`;
|
|
74648
75272
|
const revision = latest.revision + 1;
|
|
74649
75273
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
74650
75274
|
await getDb().batch([
|
|
@@ -74668,7 +75292,7 @@ async function updateCommonsEditorialArticle(input, user) {
|
|
|
74668
75292
|
JSON.stringify(nextArticles),
|
|
74669
75293
|
html,
|
|
74670
75294
|
rendered.filename,
|
|
74671
|
-
(0,
|
|
75295
|
+
(0, import_node_crypto49.createHash)("sha256").update(html).digest("hex"),
|
|
74672
75296
|
rendered.articleCount,
|
|
74673
75297
|
rendered.wordCount,
|
|
74674
75298
|
Buffer.byteLength(html),
|
|
@@ -74873,11 +75497,11 @@ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
|
|
|
74873
75497
|
"</head>"
|
|
74874
75498
|
].join("\n"));
|
|
74875
75499
|
}
|
|
74876
|
-
var
|
|
75500
|
+
var import_node_crypto49, PUBLICATION_ROOT_DOMAIN, RESERVED_SUBDOMAINS, CommonsPublicationError;
|
|
74877
75501
|
var init_commons_publication_repository = __esm({
|
|
74878
75502
|
"src/api/commons-publication-repository.ts"() {
|
|
74879
75503
|
"use strict";
|
|
74880
|
-
|
|
75504
|
+
import_node_crypto49 = require("crypto");
|
|
74881
75505
|
init_db();
|
|
74882
75506
|
init_commons_repository();
|
|
74883
75507
|
init_render();
|
|
@@ -74964,6 +75588,18 @@ function repositoryStatus(error) {
|
|
|
74964
75588
|
if (error.httpStatus === 409) return 409;
|
|
74965
75589
|
return 400;
|
|
74966
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
|
+
}
|
|
74967
75603
|
async function publicationOperation(c, operation, successStatus = 200) {
|
|
74968
75604
|
try {
|
|
74969
75605
|
return c.json({ ok: true, data: await operation() }, successStatus);
|
|
@@ -75304,7 +75940,7 @@ var init_commons_routes = __esm({
|
|
|
75304
75940
|
return c.json({ ok: true, data: hosted }, hosted.reused ? 200 : 201);
|
|
75305
75941
|
} catch (error) {
|
|
75306
75942
|
if (error instanceof CommonsImageError) {
|
|
75307
|
-
return c
|
|
75943
|
+
return imageErrorResponse(c, error);
|
|
75308
75944
|
}
|
|
75309
75945
|
throw error;
|
|
75310
75946
|
}
|
|
@@ -75368,7 +76004,14 @@ var init_commons_routes = __esm({
|
|
|
75368
76004
|
}
|
|
75369
76005
|
return c.json({ ok: true, data: result, billing: publicListingWriteBilling(billing) }, 201);
|
|
75370
76006
|
} catch (error) {
|
|
75371
|
-
|
|
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
|
+
}
|
|
75372
76015
|
if (error instanceof CommonsRepositoryError) {
|
|
75373
76016
|
return c.json({ ok: false, error: error.code, message: error.message }, repositoryStatus(error));
|
|
75374
76017
|
}
|
|
@@ -76110,7 +76753,7 @@ async function migrateAnalytics() {
|
|
|
76110
76753
|
}
|
|
76111
76754
|
function normalizeSlug2(value) {
|
|
76112
76755
|
const slug4 = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
76113
|
-
return slug4 || `site-${(0,
|
|
76756
|
+
return slug4 || `site-${(0, import_node_crypto50.randomBytes)(4).toString("hex")}`;
|
|
76114
76757
|
}
|
|
76115
76758
|
function normalizeObservedHostname(origin) {
|
|
76116
76759
|
if (!origin || origin === "null") return null;
|
|
@@ -76123,7 +76766,7 @@ function normalizeObservedHostname(origin) {
|
|
|
76123
76766
|
}
|
|
76124
76767
|
}
|
|
76125
76768
|
function publicPixelId() {
|
|
76126
|
-
return `px_${(0,
|
|
76769
|
+
return `px_${(0, import_node_crypto50.randomBytes)(18).toString("base64url")}`;
|
|
76127
76770
|
}
|
|
76128
76771
|
function mapRows(rows) {
|
|
76129
76772
|
return rows;
|
|
@@ -76155,7 +76798,7 @@ async function requireEditor(client2, siteId, userId) {
|
|
|
76155
76798
|
async function createAnalyticsSite(input) {
|
|
76156
76799
|
const db = getAnalyticsPool();
|
|
76157
76800
|
const client2 = await db.connect();
|
|
76158
|
-
const id = (0,
|
|
76801
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76159
76802
|
const baseSlug = normalizeSlug2(input.slug || input.name);
|
|
76160
76803
|
try {
|
|
76161
76804
|
await client2.query("BEGIN");
|
|
@@ -76171,7 +76814,7 @@ async function createAnalyticsSite(input) {
|
|
|
76171
76814
|
} catch (error) {
|
|
76172
76815
|
const code = error.code;
|
|
76173
76816
|
if (code !== "23505" || attempt === 2) throw error;
|
|
76174
|
-
slug4 = `${baseSlug}-${(0,
|
|
76817
|
+
slug4 = `${baseSlug}-${(0, import_node_crypto50.randomBytes)(2).toString("hex")}`;
|
|
76175
76818
|
}
|
|
76176
76819
|
}
|
|
76177
76820
|
await client2.query(
|
|
@@ -76386,7 +77029,7 @@ async function createAnalyticsPixel(input) {
|
|
|
76386
77029
|
VALUES ($1, $2, $3, $4, $5)
|
|
76387
77030
|
RETURNING id, site_id, public_id, name, environment, status, created_at::text, NULL::text AS last_event_at`,
|
|
76388
77031
|
[
|
|
76389
|
-
(0,
|
|
77032
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76390
77033
|
input.siteId,
|
|
76391
77034
|
publicPixelId(),
|
|
76392
77035
|
input.name.trim(),
|
|
@@ -76463,7 +77106,7 @@ async function setAnalyticsPixelDomainState(input) {
|
|
|
76463
77106
|
SELECT $1, p.id, $4, $5 FROM analytics_pixels p WHERE p.id = $2 AND p.site_id = $3
|
|
76464
77107
|
ON CONFLICT(pixel_id, hostname) DO UPDATE SET state = EXCLUDED.state, updated_at = now()
|
|
76465
77108
|
RETURNING id`,
|
|
76466
|
-
[(0,
|
|
77109
|
+
[(0, import_node_crypto50.randomUUID)(), input.pixelId, input.siteId, hostname, input.state]
|
|
76467
77110
|
);
|
|
76468
77111
|
if (!result.rowCount)
|
|
76469
77112
|
throw new AnalyticsRepositoryError(
|
|
@@ -76513,7 +77156,7 @@ function sanitizeAnalyticsProperties(value) {
|
|
|
76513
77156
|
}
|
|
76514
77157
|
async function ingestAnalyticsEvents(input) {
|
|
76515
77158
|
const db = getAnalyticsPool();
|
|
76516
|
-
const requestId = `air_${(0,
|
|
77159
|
+
const requestId = `air_${(0, import_node_crypto50.randomUUID)()}`;
|
|
76517
77160
|
const hostname = normalizeObservedHostname(input.origin);
|
|
76518
77161
|
const pixelResult = await db.query(
|
|
76519
77162
|
`SELECT p.id, p.site_id, p.status,
|
|
@@ -76534,7 +77177,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76534
77177
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
76535
77178
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
76536
77179
|
[
|
|
76537
|
-
(0,
|
|
77180
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76538
77181
|
requestId,
|
|
76539
77182
|
pixel?.site_id ?? null,
|
|
76540
77183
|
pixel?.id ?? null,
|
|
@@ -76559,7 +77202,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76559
77202
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
76560
77203
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
76561
77204
|
[
|
|
76562
|
-
(0,
|
|
77205
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76563
77206
|
requestId,
|
|
76564
77207
|
pixel.site_id,
|
|
76565
77208
|
pixel.id,
|
|
@@ -76584,7 +77227,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76584
77227
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, rejected_count, reason_codes)
|
|
76585
77228
|
VALUES ($1, $2, $3, $4, $5, $6::jsonb)`,
|
|
76586
77229
|
[
|
|
76587
|
-
(0,
|
|
77230
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76588
77231
|
requestId,
|
|
76589
77232
|
pixel.site_id,
|
|
76590
77233
|
pixel.id,
|
|
@@ -76608,7 +77251,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76608
77251
|
ON CONFLICT(pixel_id, hostname) DO UPDATE
|
|
76609
77252
|
SET last_seen_at = now(), updated_at = now()
|
|
76610
77253
|
RETURNING state`,
|
|
76611
|
-
[(0,
|
|
77254
|
+
[(0, import_node_crypto50.randomUUID)(), pixel.id, hostname]
|
|
76612
77255
|
);
|
|
76613
77256
|
if (domainResult.rows[0]?.state !== "approved") {
|
|
76614
77257
|
await db.query(
|
|
@@ -76622,7 +77265,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76622
77265
|
`INSERT INTO analytics_ingestion_receipts(id, request_id, site_id, pixel_id, hostname, rejected_count, reason_codes)
|
|
76623
77266
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
|
|
76624
77267
|
[
|
|
76625
|
-
(0,
|
|
77268
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76626
77269
|
requestId,
|
|
76627
77270
|
pixel.site_id,
|
|
76628
77271
|
pixel.id,
|
|
@@ -76672,7 +77315,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76672
77315
|
$23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33
|
|
76673
77316
|
) ON CONFLICT(site_id, event_id) DO NOTHING`,
|
|
76674
77317
|
[
|
|
76675
|
-
(0,
|
|
77318
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76676
77319
|
event2.eventId,
|
|
76677
77320
|
pixel.site_id,
|
|
76678
77321
|
pixel.id,
|
|
@@ -76730,7 +77373,7 @@ async function ingestAnalyticsEvents(input) {
|
|
|
76730
77373
|
id, request_id, site_id, pixel_id, hostname, accepted_count, rejected_count, reason_codes
|
|
76731
77374
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb)`,
|
|
76732
77375
|
[
|
|
76733
|
-
(0,
|
|
77376
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
76734
77377
|
requestId,
|
|
76735
77378
|
pixel.site_id,
|
|
76736
77379
|
pixel.id,
|
|
@@ -76762,7 +77405,7 @@ function normalizeGeographyCode(value, max) {
|
|
|
76762
77405
|
return normalized && /^[A-Z0-9-]+$/.test(normalized) ? normalized.slice(0, max) : null;
|
|
76763
77406
|
}
|
|
76764
77407
|
function pageFingerprint(scope, siteId, filters) {
|
|
76765
|
-
return (0,
|
|
77408
|
+
return (0, import_node_crypto50.createHash)("sha256").update(JSON.stringify({ scope, siteId, filters })).digest("base64url").slice(0, 18);
|
|
76766
77409
|
}
|
|
76767
77410
|
function decodePageOffset(cursor, fingerprint2) {
|
|
76768
77411
|
if (!cursor) return 0;
|
|
@@ -76812,7 +77455,7 @@ async function createAnalyticsConversion(input) {
|
|
|
76812
77455
|
404
|
|
76813
77456
|
);
|
|
76814
77457
|
}
|
|
76815
|
-
const id = (0,
|
|
77458
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
76816
77459
|
const resolvedPerson = input.sessionId ? await db.query(
|
|
76817
77460
|
`SELECT e.person_id FROM analytics_identity_nodes n JOIN analytics_identity_edges e ON e.identity_node_id = n.id
|
|
76818
77461
|
WHERE n.site_id = $1 AND n.kind = 'session_id' AND n.value_hmac = $2 ORDER BY e.confidence DESC LIMIT 1`,
|
|
@@ -77561,7 +78204,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
77561
78204
|
404
|
|
77562
78205
|
);
|
|
77563
78206
|
}
|
|
77564
|
-
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);
|
|
77565
78208
|
try {
|
|
77566
78209
|
const result = await db.query(
|
|
77567
78210
|
`INSERT INTO analytics_campaign_links(
|
|
@@ -77570,7 +78213,7 @@ async function createAnalyticsCampaignLink(input) {
|
|
|
77570
78213
|
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
|
|
77571
78214
|
RETURNING *, 0::int AS click_count`,
|
|
77572
78215
|
[
|
|
77573
|
-
(0,
|
|
78216
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77574
78217
|
input.siteId,
|
|
77575
78218
|
input.pixelId ?? null,
|
|
77576
78219
|
input.name.trim(),
|
|
@@ -77641,7 +78284,7 @@ async function resolveAnalyticsCampaignLink(shortCode, referrer) {
|
|
|
77641
78284
|
if (!row) return null;
|
|
77642
78285
|
await db.query(
|
|
77643
78286
|
`INSERT INTO analytics_campaign_clicks(id, link_id, referrer) VALUES ($1, $2, $3)`,
|
|
77644
|
-
[(0,
|
|
78287
|
+
[(0, import_node_crypto50.randomUUID)(), row.id, normalizeAnalyticsUrl(referrer || void 0)]
|
|
77645
78288
|
);
|
|
77646
78289
|
return buildTaggedCampaignUrl(row);
|
|
77647
78290
|
}
|
|
@@ -77659,14 +78302,14 @@ async function createAnalyticsForm(input) {
|
|
|
77659
78302
|
404
|
|
77660
78303
|
);
|
|
77661
78304
|
const baseSlug = normalizeSlug2(input.name);
|
|
77662
|
-
const slug4 = `${baseSlug}-${(0,
|
|
77663
|
-
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")}`;
|
|
77664
78307
|
const result = await db.query(
|
|
77665
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)
|
|
77666
78309
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8::jsonb,$9,$10,$11,$12,$13,$14)
|
|
77667
78310
|
RETURNING *, 0::int AS submission_count`,
|
|
77668
78311
|
[
|
|
77669
|
-
(0,
|
|
78312
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77670
78313
|
publicId,
|
|
77671
78314
|
input.siteId,
|
|
77672
78315
|
input.pixelId,
|
|
@@ -77711,7 +78354,7 @@ async function getPublicAnalyticsForm(publicId) {
|
|
|
77711
78354
|
return result.rows[0] ?? null;
|
|
77712
78355
|
}
|
|
77713
78356
|
async function recordAnalyticsFormSubmission(input) {
|
|
77714
|
-
const id = (0,
|
|
78357
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
77715
78358
|
await getAnalyticsPool().query(
|
|
77716
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)
|
|
77717
78360
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb)`,
|
|
@@ -77742,7 +78385,7 @@ function sanitizeClickIds(value) {
|
|
|
77742
78385
|
return output;
|
|
77743
78386
|
}
|
|
77744
78387
|
function identityHmac(kind, value) {
|
|
77745
|
-
return (0,
|
|
78388
|
+
return (0, import_node_crypto50.createHmac)("sha256", getSessionSecret()).update(`${kind}:${value.trim().toLowerCase()}`).digest("hex");
|
|
77746
78389
|
}
|
|
77747
78390
|
async function linkAnalyticsFormIdentity(input) {
|
|
77748
78391
|
const client2 = await getAnalyticsPool().connect();
|
|
@@ -77751,7 +78394,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
77751
78394
|
const person = await client2.query(
|
|
77752
78395
|
`INSERT INTO analytics_people(id, site_id, crm_person_ref) VALUES ($1,$2,$3)
|
|
77753
78396
|
ON CONFLICT(site_id, crm_person_ref) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
77754
|
-
[(0,
|
|
78397
|
+
[(0, import_node_crypto50.randomUUID)(), input.siteId, input.crmPersonRef]
|
|
77755
78398
|
);
|
|
77756
78399
|
const personId = person.rows[0].id;
|
|
77757
78400
|
const signals = [];
|
|
@@ -77798,7 +78441,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
77798
78441
|
`INSERT INTO analytics_identity_nodes(id, site_id, kind, value_hmac) VALUES ($1,$2,$3,$4)
|
|
77799
78442
|
ON CONFLICT(site_id, kind, value_hmac) DO UPDATE SET last_seen_at = now() RETURNING id`,
|
|
77800
78443
|
[
|
|
77801
|
-
(0,
|
|
78444
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77802
78445
|
input.siteId,
|
|
77803
78446
|
signal.kind,
|
|
77804
78447
|
identityHmac(signal.kind, signal.value)
|
|
@@ -77809,7 +78452,7 @@ async function linkAnalyticsFormIdentity(input) {
|
|
|
77809
78452
|
VALUES ($1,$2,$3,$4,$5,$6)
|
|
77810
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)`,
|
|
77811
78454
|
[
|
|
77812
|
-
(0,
|
|
78455
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77813
78456
|
input.siteId,
|
|
77814
78457
|
personId,
|
|
77815
78458
|
node.rows[0].id,
|
|
@@ -77907,7 +78550,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
77907
78550
|
const db = getAnalyticsPool();
|
|
77908
78551
|
await requireEditor(db, input.siteId, input.userId);
|
|
77909
78552
|
const client2 = await db.connect();
|
|
77910
|
-
const id = (0,
|
|
78553
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
77911
78554
|
try {
|
|
77912
78555
|
await client2.query("BEGIN");
|
|
77913
78556
|
await client2.query(
|
|
@@ -77927,7 +78570,7 @@ async function createAnalyticsCrmImport(input) {
|
|
|
77927
78570
|
await client2.query(
|
|
77928
78571
|
`INSERT INTO analytics_crm_import_rows(id, import_id, crm_person_ref, payload_ciphertext)
|
|
77929
78572
|
VALUES ($1,$2,$3,$4) ON CONFLICT(import_id, crm_person_ref) DO NOTHING`,
|
|
77930
|
-
[(0,
|
|
78573
|
+
[(0, import_node_crypto50.randomUUID)(), id, row.crmPersonRef, row.payloadCiphertext]
|
|
77931
78574
|
);
|
|
77932
78575
|
}
|
|
77933
78576
|
await client2.query("COMMIT");
|
|
@@ -77966,7 +78609,7 @@ async function createAnalyticsActivationDestination(input) {
|
|
|
77966
78609
|
`INSERT INTO analytics_activation_destinations(id, site_id, platform, name, connection_ref, external_dataset_id, event_mapping, created_by_user_id)
|
|
77967
78610
|
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8) RETURNING *`,
|
|
77968
78611
|
[
|
|
77969
|
-
(0,
|
|
78612
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
77970
78613
|
input.siteId,
|
|
77971
78614
|
input.platform,
|
|
77972
78615
|
input.name.trim(),
|
|
@@ -78018,7 +78661,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
78018
78661
|
`INSERT INTO analytics_activation_jobs(id, destination_id, conversion_id, person_id, payload_ciphertext)
|
|
78019
78662
|
VALUES ($1,$2,$3,$4,$5) ON CONFLICT(destination_id, conversion_id) DO NOTHING`,
|
|
78020
78663
|
[
|
|
78021
|
-
(0,
|
|
78664
|
+
(0, import_node_crypto50.randomUUID)(),
|
|
78022
78665
|
destination.id,
|
|
78023
78666
|
input.conversionId,
|
|
78024
78667
|
input.personId ?? null,
|
|
@@ -78030,7 +78673,7 @@ async function queueAnalyticsActivation(input) {
|
|
|
78030
78673
|
return queued;
|
|
78031
78674
|
}
|
|
78032
78675
|
async function queueAnalyticsFormDelivery(input) {
|
|
78033
|
-
const id = (0,
|
|
78676
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
78034
78677
|
await getAnalyticsPool().query(
|
|
78035
78678
|
`INSERT INTO analytics_form_delivery_jobs(id, submission_id, owner_user_id, payload_ciphertext, last_error_code)
|
|
78036
78679
|
VALUES ($1,$2,$3,$4,$5)`,
|
|
@@ -78157,7 +78800,7 @@ async function analyticsHealth(siteId, userId) {
|
|
|
78157
78800
|
}
|
|
78158
78801
|
async function refreshAnalyticsDailyRollups(input) {
|
|
78159
78802
|
const db = getAnalyticsPool();
|
|
78160
|
-
const runId = (0,
|
|
78803
|
+
const runId = (0, import_node_crypto50.randomUUID)();
|
|
78161
78804
|
await db.query(
|
|
78162
78805
|
`INSERT INTO analytics_rollup_runs(id, window_start, window_end, status) VALUES ($1, $2, $3, 'running')`,
|
|
78163
78806
|
[runId, input.start, input.end]
|
|
@@ -78354,7 +78997,7 @@ async function createAnalyticsExport(input) {
|
|
|
78354
78997
|
`Generated ${(/* @__PURE__ */ new Date()).toISOString()} from the governed ${input.report} report contract.`
|
|
78355
78998
|
].join("\n");
|
|
78356
78999
|
}
|
|
78357
|
-
const id = (0,
|
|
79000
|
+
const id = (0, import_node_crypto50.randomUUID)();
|
|
78358
79001
|
const inserted = await getAnalyticsPool().query(
|
|
78359
79002
|
`INSERT INTO analytics_exports(id, site_id, requested_by_user_id, idempotency_key, report, format, filters, content)
|
|
78360
79003
|
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8)
|
|
@@ -78387,11 +79030,11 @@ async function createAnalyticsExport(input) {
|
|
|
78387
79030
|
}
|
|
78388
79031
|
return describeArtifact(replay.rows[0]);
|
|
78389
79032
|
}
|
|
78390
|
-
var
|
|
79033
|
+
var import_node_crypto50, import_pg, AnalyticsRepositoryError, pool2, MAX_ENGAGED_MS, ENGAGED_SESSION_MS, blockedPropertyName, inferredFamilySql, ANALYTICS_CONTENT_SORTS, clickIdKeys;
|
|
78391
79034
|
var init_analytics_repository = __esm({
|
|
78392
79035
|
"src/api/analytics-repository.ts"() {
|
|
78393
79036
|
"use strict";
|
|
78394
|
-
|
|
79037
|
+
import_node_crypto50 = require("crypto");
|
|
78395
79038
|
import_pg = require("pg");
|
|
78396
79039
|
init_session();
|
|
78397
79040
|
init_analytics_attribution();
|
|
@@ -78630,8 +79273,8 @@ function dashboardCallbackUrl() {
|
|
|
78630
79273
|
}
|
|
78631
79274
|
async function createThorbitConnectUrl(userId) {
|
|
78632
79275
|
if (!bridgeConfigured()) throw new Error("Thorbit X-Ray account bridge is not configured");
|
|
78633
|
-
const state = (0,
|
|
78634
|
-
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");
|
|
78635
79278
|
await getAnalyticsPool().query(
|
|
78636
79279
|
`INSERT INTO analytics_thorbit_connect_states(state_hash,user_id,expires_at)
|
|
78637
79280
|
VALUES ($1,$2,now()+interval '10 minutes')
|
|
@@ -78646,9 +79289,9 @@ async function createThorbitConnectUrl(userId) {
|
|
|
78646
79289
|
function verifyThorbitAssertion(token6) {
|
|
78647
79290
|
const [encoded, signature] = token6.split(".");
|
|
78648
79291
|
if (!encoded || !signature || !bridgeConfigured()) throw new Error("Invalid Thorbit assertion");
|
|
78649
|
-
const expected = (0,
|
|
79292
|
+
const expected = (0, import_node_crypto51.createHmac)("sha256", bridgeSecret()).update(encoded).digest();
|
|
78650
79293
|
const actual = Buffer.from(signature, "base64url");
|
|
78651
|
-
if (actual.length !== expected.length || !(0,
|
|
79294
|
+
if (actual.length !== expected.length || !(0, import_node_crypto51.timingSafeEqual)(actual, expected)) {
|
|
78652
79295
|
throw new Error("Invalid Thorbit assertion signature");
|
|
78653
79296
|
}
|
|
78654
79297
|
const parsed = AssertionSchema.safeParse(
|
|
@@ -78660,7 +79303,7 @@ function verifyThorbitAssertion(token6) {
|
|
|
78660
79303
|
return parsed.data.entitlement;
|
|
78661
79304
|
}
|
|
78662
79305
|
async function consumeThorbitConnectCallback(input) {
|
|
78663
|
-
const stateHash = (0,
|
|
79306
|
+
const stateHash = (0, import_node_crypto51.createHash)("sha256").update(input.state).digest("hex");
|
|
78664
79307
|
const client2 = await getAnalyticsPool().connect();
|
|
78665
79308
|
try {
|
|
78666
79309
|
await client2.query("BEGIN");
|
|
@@ -78700,11 +79343,11 @@ async function disconnectAnalyticsEntitlement(userId) {
|
|
|
78700
79343
|
[userId]
|
|
78701
79344
|
);
|
|
78702
79345
|
}
|
|
78703
|
-
var
|
|
79346
|
+
var import_node_crypto51, import_zod55, THORBIT_PRODUCT_URL, REFRESH_INTERVAL_MS, ELIGIBLE_GRACE_MS, TRIAL_LENGTH_MS, ThorbitEntitlementSchema, AssertionSchema;
|
|
78704
79347
|
var init_analytics_entitlement = __esm({
|
|
78705
79348
|
"src/api/analytics-entitlement.ts"() {
|
|
78706
79349
|
"use strict";
|
|
78707
|
-
|
|
79350
|
+
import_node_crypto51 = require("crypto");
|
|
78708
79351
|
import_zod55 = require("zod");
|
|
78709
79352
|
init_analytics_repository();
|
|
78710
79353
|
THORBIT_PRODUCT_URL = "https://thorbit.ai";
|
|
@@ -78844,14 +79487,14 @@ function renderPublicForm(form, placementUrl) {
|
|
|
78844
79487
|
const brand = form.brand;
|
|
78845
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>`;
|
|
78846
79489
|
}
|
|
78847
|
-
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;
|
|
78848
79491
|
var init_analytics_routes = __esm({
|
|
78849
79492
|
"src/api/analytics-routes.ts"() {
|
|
78850
79493
|
"use strict";
|
|
78851
79494
|
import_hono34 = require("hono");
|
|
78852
79495
|
import_factory6 = require("hono/factory");
|
|
78853
79496
|
import_zod56 = require("zod");
|
|
78854
|
-
|
|
79497
|
+
import_node_crypto52 = require("crypto");
|
|
78855
79498
|
import_papaparse6 = __toESM(require("papaparse"), 1);
|
|
78856
79499
|
init_api_auth();
|
|
78857
79500
|
init_db();
|
|
@@ -79182,7 +79825,7 @@ var init_analytics_routes = __esm({
|
|
|
79182
79825
|
const lastName = typeof data.last_name === "string" ? data.last_name.trim() : "";
|
|
79183
79826
|
const fullName = [firstName, lastName].filter(Boolean).join(" ") || (typeof data.name === "string" ? data.name.trim() : "") || email || "Website lead";
|
|
79184
79827
|
const identitySeed = email || `${fullName}:${Date.now()}`;
|
|
79185
|
-
const suffix2 = (0,
|
|
79828
|
+
const suffix2 = (0, import_node_crypto52.createHash)("sha256").update(identitySeed).digest("hex").slice(0, 12);
|
|
79186
79829
|
const path6 = `Leads/person-${suffix2}`;
|
|
79187
79830
|
const { key: memoryKey, error: memoryKeyError } = await getOrCreateUserMemoryKey(user);
|
|
79188
79831
|
const existing = memoryKey ? await memoryCall("getTool", { vault: "People", path: path6 }, memoryKey) : { ok: false, error: memoryKeyError || "memory_credential_unavailable" };
|
|
@@ -79281,9 +79924,9 @@ Submitted the published form.
|
|
|
79281
79924
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
79282
79925
|
});
|
|
79283
79926
|
const match = {
|
|
79284
|
-
...email ? { emailSha256: (0,
|
|
79927
|
+
...email ? { emailSha256: (0, import_node_crypto52.createHash)("sha256").update(email).digest("hex") } : {},
|
|
79285
79928
|
...phone ? {
|
|
79286
|
-
phoneSha256: (0,
|
|
79929
|
+
phoneSha256: (0, import_node_crypto52.createHash)("sha256").update(phone.replace(/\D/g, "")).digest("hex")
|
|
79287
79930
|
} : {}
|
|
79288
79931
|
};
|
|
79289
79932
|
const activationQueued = await queueAnalyticsActivation({
|
|
@@ -79711,7 +80354,7 @@ Submitted the published form.
|
|
|
79711
80354
|
rejectedCount += 1;
|
|
79712
80355
|
continue;
|
|
79713
80356
|
}
|
|
79714
|
-
const digest2 = (0,
|
|
80357
|
+
const digest2 = (0, import_node_crypto52.createHash)("sha256").update(
|
|
79715
80358
|
`${parsed.data.sourceSystem}:${externalId || email || phone || `${fullName}:${index}`}`
|
|
79716
80359
|
).digest("hex").slice(0, 16);
|
|
79717
80360
|
const path6 = `Leads/person-${digest2}`;
|
|
@@ -80169,19 +80812,19 @@ var init_analytics_delivery = __esm({
|
|
|
80169
80812
|
|
|
80170
80813
|
// src/api/scheduled-artifact-owner.ts
|
|
80171
80814
|
function scheduledArtifactOwnerIdForApiKey(apiKey) {
|
|
80172
|
-
return (0,
|
|
80815
|
+
return (0, import_node_crypto53.createHash)("sha256").update(apiKey).digest("hex").slice(0, 24);
|
|
80173
80816
|
}
|
|
80174
|
-
var
|
|
80817
|
+
var import_node_crypto53;
|
|
80175
80818
|
var init_scheduled_artifact_owner = __esm({
|
|
80176
80819
|
"src/api/scheduled-artifact-owner.ts"() {
|
|
80177
80820
|
"use strict";
|
|
80178
|
-
|
|
80821
|
+
import_node_crypto53 = require("crypto");
|
|
80179
80822
|
}
|
|
80180
80823
|
});
|
|
80181
80824
|
|
|
80182
80825
|
// src/api/scheduled-run-view-links.ts
|
|
80183
80826
|
async function ensureScheduledRunViewLinksSchema() {
|
|
80184
|
-
if (
|
|
80827
|
+
if (schemaReady3) return;
|
|
80185
80828
|
const db = getDb();
|
|
80186
80829
|
await db.execute(`
|
|
80187
80830
|
CREATE TABLE IF NOT EXISTS scheduled_run_view_links (
|
|
@@ -80229,10 +80872,10 @@ async function ensureScheduledRunViewLinksSchema() {
|
|
|
80229
80872
|
CREATE INDEX IF NOT EXISTS scheduled_run_view_links_expiry
|
|
80230
80873
|
ON scheduled_run_view_links(expires_at, revoked_at)
|
|
80231
80874
|
`);
|
|
80232
|
-
|
|
80875
|
+
schemaReady3 = true;
|
|
80233
80876
|
}
|
|
80234
80877
|
function tokenHash2(token6) {
|
|
80235
|
-
return (0,
|
|
80878
|
+
return (0, import_node_crypto54.createHash)("sha256").update(token6).digest("hex");
|
|
80236
80879
|
}
|
|
80237
80880
|
function mapRow(row) {
|
|
80238
80881
|
return {
|
|
@@ -80252,9 +80895,9 @@ function mapRow(row) {
|
|
|
80252
80895
|
async function createScheduledRunViewLink(input) {
|
|
80253
80896
|
await ensureScheduledRunViewLinksSchema();
|
|
80254
80897
|
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
80255
|
-
const token6 = (0,
|
|
80898
|
+
const token6 = (0, import_node_crypto54.randomBytes)(32).toString("base64url");
|
|
80256
80899
|
const record = {
|
|
80257
|
-
shareId: (0,
|
|
80900
|
+
shareId: (0, import_node_crypto54.randomUUID)(),
|
|
80258
80901
|
ownerId: input.ownerId,
|
|
80259
80902
|
runId: input.runId,
|
|
80260
80903
|
artifactId: input.artifactId,
|
|
@@ -80317,13 +80960,13 @@ async function revokeScheduledRunViewLink(ownerId2, runId, shareId, now = /* @__
|
|
|
80317
80960
|
});
|
|
80318
80961
|
return result.rowsAffected > 0;
|
|
80319
80962
|
}
|
|
80320
|
-
var
|
|
80963
|
+
var import_node_crypto54, schemaReady3;
|
|
80321
80964
|
var init_scheduled_run_view_links = __esm({
|
|
80322
80965
|
"src/api/scheduled-run-view-links.ts"() {
|
|
80323
80966
|
"use strict";
|
|
80324
|
-
|
|
80967
|
+
import_node_crypto54 = require("crypto");
|
|
80325
80968
|
init_db();
|
|
80326
|
-
|
|
80969
|
+
schemaReady3 = false;
|
|
80327
80970
|
}
|
|
80328
80971
|
});
|
|
80329
80972
|
|
|
@@ -80387,15 +81030,15 @@ ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id=
|
|
|
80387
81030
|
html,
|
|
80388
81031
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
80389
81032
|
bytes,
|
|
80390
|
-
sha256: (0,
|
|
81033
|
+
sha256: (0, import_node_crypto55.createHash)("sha256").update(html).digest("hex"),
|
|
80391
81034
|
generatedAt: generatedAtIso
|
|
80392
81035
|
};
|
|
80393
81036
|
}
|
|
80394
|
-
var
|
|
81037
|
+
var import_node_crypto55;
|
|
80395
81038
|
var init_render2 = __esm({
|
|
80396
81039
|
"src/personal-authority/render.ts"() {
|
|
80397
81040
|
"use strict";
|
|
80398
|
-
|
|
81041
|
+
import_node_crypto55 = require("crypto");
|
|
80399
81042
|
}
|
|
80400
81043
|
});
|
|
80401
81044
|
|
|
@@ -80498,15 +81141,15 @@ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id
|
|
|
80498
81141
|
html,
|
|
80499
81142
|
filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
|
|
80500
81143
|
bytes,
|
|
80501
|
-
sha256: (0,
|
|
81144
|
+
sha256: (0, import_node_crypto56.createHash)("sha256").update(html).digest("hex"),
|
|
80502
81145
|
generatedAt: generatedAtIso
|
|
80503
81146
|
};
|
|
80504
81147
|
}
|
|
80505
|
-
var
|
|
81148
|
+
var import_node_crypto56, FONT_STACKS;
|
|
80506
81149
|
var init_render_v2 = __esm({
|
|
80507
81150
|
"src/personal-authority/render-v2.ts"() {
|
|
80508
81151
|
"use strict";
|
|
80509
|
-
|
|
81152
|
+
import_node_crypto56 = require("crypto");
|
|
80510
81153
|
init_contracts();
|
|
80511
81154
|
FONT_STACKS = Object.freeze({
|
|
80512
81155
|
"editorial-serif": "Iowan Old Style, Baskerville, Times New Roman, serif",
|
|
@@ -80622,15 +81265,15 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
80622
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}}
|
|
80623
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>`;
|
|
80624
81267
|
const bytes = Buffer.byteLength(html);
|
|
80625
|
-
const sha2565 = (0,
|
|
81268
|
+
const sha2565 = (0, import_node_crypto57.createHash)("sha256").update(html).digest("hex");
|
|
80626
81269
|
const filename2 = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
|
|
80627
81270
|
return { html, filename: filename2, bytes, sha256: sha2565, generatedAt: generatedAtIso };
|
|
80628
81271
|
}
|
|
80629
|
-
var
|
|
81272
|
+
var import_node_crypto57;
|
|
80630
81273
|
var init_render3 = __esm({
|
|
80631
81274
|
"src/newsroom-publisher/render.ts"() {
|
|
80632
81275
|
"use strict";
|
|
80633
|
-
|
|
81276
|
+
import_node_crypto57 = require("crypto");
|
|
80634
81277
|
}
|
|
80635
81278
|
});
|
|
80636
81279
|
|
|
@@ -80722,7 +81365,7 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
80722
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}}
|
|
80723
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>`;
|
|
80724
81367
|
const bytes = Buffer.byteLength(html);
|
|
80725
|
-
const sha2565 = (0,
|
|
81368
|
+
const sha2565 = (0, import_node_crypto58.createHash)("sha256").update(html).digest("hex");
|
|
80726
81369
|
return {
|
|
80727
81370
|
html,
|
|
80728
81371
|
filename: "blog-article.html",
|
|
@@ -80732,11 +81375,11 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
80732
81375
|
generatedAt: generatedAtIso
|
|
80733
81376
|
};
|
|
80734
81377
|
}
|
|
80735
|
-
var
|
|
81378
|
+
var import_node_crypto58;
|
|
80736
81379
|
var init_render4 = __esm({
|
|
80737
81380
|
"src/blog-article/render.ts"() {
|
|
80738
81381
|
"use strict";
|
|
80739
|
-
|
|
81382
|
+
import_node_crypto58 = require("crypto");
|
|
80740
81383
|
}
|
|
80741
81384
|
});
|
|
80742
81385
|
|
|
@@ -81067,7 +81710,7 @@ function policy6() {
|
|
|
81067
81710
|
};
|
|
81068
81711
|
}
|
|
81069
81712
|
function runStorageSegment(runId) {
|
|
81070
|
-
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)}`;
|
|
81071
81714
|
}
|
|
81072
81715
|
async function createScheduledRunArtifact(args) {
|
|
81073
81716
|
if (args.rendered.bytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) {
|
|
@@ -81108,12 +81751,12 @@ async function readScheduledRunArtifact(args) {
|
|
|
81108
81751
|
if (!window2 || window2.nextOffset !== null || window2.totalBytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) return null;
|
|
81109
81752
|
return window2.text;
|
|
81110
81753
|
}
|
|
81111
|
-
var
|
|
81754
|
+
var import_node_crypto59, SCHEDULED_RUN_ARTIFACT_PREFIX, SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS, SCHEDULED_RUN_ARTIFACT_MAX_BYTES;
|
|
81112
81755
|
var init_scheduled_run_artifact_store = __esm({
|
|
81113
81756
|
"src/scheduled-artifacts/scheduled-run-artifact-store.ts"() {
|
|
81114
81757
|
"use strict";
|
|
81115
81758
|
init_private_artifacts();
|
|
81116
|
-
|
|
81759
|
+
import_node_crypto59 = require("crypto");
|
|
81117
81760
|
SCHEDULED_RUN_ARTIFACT_PREFIX = "scheduled-run-artifacts/";
|
|
81118
81761
|
SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS = 15 * 60 * 1e3;
|
|
81119
81762
|
SCHEDULED_RUN_ARTIFACT_MAX_BYTES = 2e6;
|
|
@@ -81191,357 +81834,6 @@ var init_public_scheduled_result_routes = __esm({
|
|
|
81191
81834
|
}
|
|
81192
81835
|
});
|
|
81193
81836
|
|
|
81194
|
-
// src/api/service-connections.ts
|
|
81195
|
-
function ensureServiceConnectionsSchema() {
|
|
81196
|
-
const currentDb = getDb();
|
|
81197
|
-
if (schemaReady3 && schemaDb6 === currentDb) return schemaReady3;
|
|
81198
|
-
schemaDb6 = currentDb;
|
|
81199
|
-
schemaReady3 = (async () => {
|
|
81200
|
-
const db = currentDb;
|
|
81201
|
-
await db.execute(`
|
|
81202
|
-
CREATE TABLE IF NOT EXISTS service_connections (
|
|
81203
|
-
id TEXT PRIMARY KEY,
|
|
81204
|
-
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
81205
|
-
provider_config_key TEXT NOT NULL,
|
|
81206
|
-
provider TEXT,
|
|
81207
|
-
transport TEXT NOT NULL,
|
|
81208
|
-
upstream_connection_id TEXT,
|
|
81209
|
-
label TEXT,
|
|
81210
|
-
user_label TEXT,
|
|
81211
|
-
provider_account_id TEXT,
|
|
81212
|
-
provider_account_email TEXT,
|
|
81213
|
-
provider_account_name TEXT,
|
|
81214
|
-
provider_identity_checked_at TEXT,
|
|
81215
|
-
provider_identity_source_updated_at TEXT,
|
|
81216
|
-
lifecycle_status TEXT NOT NULL DEFAULT 'pending',
|
|
81217
|
-
operational_status TEXT NOT NULL DEFAULT 'unknown',
|
|
81218
|
-
reconnect_required INTEGER NOT NULL DEFAULT 0,
|
|
81219
|
-
actions_enabled INTEGER NOT NULL DEFAULT 0,
|
|
81220
|
-
read_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
81221
|
-
action_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
81222
|
-
tool_revision TEXT,
|
|
81223
|
-
last_checked_at TEXT,
|
|
81224
|
-
last_successful_call_at TEXT,
|
|
81225
|
-
last_failure_at TEXT,
|
|
81226
|
-
last_failure_code TEXT,
|
|
81227
|
-
last_failure_retryable INTEGER,
|
|
81228
|
-
consecutive_failures INTEGER NOT NULL DEFAULT 0,
|
|
81229
|
-
vault_name TEXT,
|
|
81230
|
-
table_name TEXT,
|
|
81231
|
-
legacy_owner_identity TEXT,
|
|
81232
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
81233
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
81234
|
-
UNIQUE(user_id, provider_config_key, upstream_connection_id)
|
|
81235
|
-
)
|
|
81236
|
-
`);
|
|
81237
|
-
try {
|
|
81238
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN user_label TEXT`);
|
|
81239
|
-
} catch {
|
|
81240
|
-
}
|
|
81241
|
-
try {
|
|
81242
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_id TEXT`);
|
|
81243
|
-
} catch {
|
|
81244
|
-
}
|
|
81245
|
-
try {
|
|
81246
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_email TEXT`);
|
|
81247
|
-
} catch {
|
|
81248
|
-
}
|
|
81249
|
-
try {
|
|
81250
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_account_name TEXT`);
|
|
81251
|
-
} catch {
|
|
81252
|
-
}
|
|
81253
|
-
try {
|
|
81254
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_identity_checked_at TEXT`);
|
|
81255
|
-
} catch {
|
|
81256
|
-
}
|
|
81257
|
-
try {
|
|
81258
|
-
await db.execute(`ALTER TABLE service_connections ADD COLUMN provider_identity_source_updated_at TEXT`);
|
|
81259
|
-
} catch {
|
|
81260
|
-
}
|
|
81261
|
-
await db.execute(`CREATE INDEX IF NOT EXISTS service_connections_user_updated ON service_connections(user_id, updated_at DESC)`);
|
|
81262
|
-
await db.execute(`CREATE INDEX IF NOT EXISTS service_connections_upstream ON service_connections(provider_config_key, upstream_connection_id)`);
|
|
81263
|
-
await db.execute(`
|
|
81264
|
-
CREATE TABLE IF NOT EXISTS service_connection_health_events (
|
|
81265
|
-
id TEXT PRIMARY KEY,
|
|
81266
|
-
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
81267
|
-
operational_status TEXT NOT NULL,
|
|
81268
|
-
failure_code TEXT,
|
|
81269
|
-
retryable INTEGER,
|
|
81270
|
-
evidence_source TEXT NOT NULL,
|
|
81271
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
81272
|
-
)
|
|
81273
|
-
`);
|
|
81274
|
-
await db.execute(`CREATE INDEX IF NOT EXISTS service_connection_health_events_connection ON service_connection_health_events(connection_id, created_at DESC)`);
|
|
81275
|
-
await db.execute(`
|
|
81276
|
-
CREATE TABLE IF NOT EXISTS service_connection_action_audit (
|
|
81277
|
-
id TEXT PRIMARY KEY,
|
|
81278
|
-
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
81279
|
-
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
81280
|
-
tool TEXT NOT NULL,
|
|
81281
|
-
request_id TEXT NOT NULL,
|
|
81282
|
-
status TEXT NOT NULL,
|
|
81283
|
-
error_code TEXT,
|
|
81284
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
81285
|
-
UNIQUE(user_id, request_id)
|
|
81286
|
-
)
|
|
81287
|
-
`);
|
|
81288
|
-
try {
|
|
81289
|
-
await db.execute(`ALTER TABLE service_connection_action_audit ADD COLUMN request_digest TEXT`);
|
|
81290
|
-
} catch {
|
|
81291
|
-
}
|
|
81292
|
-
try {
|
|
81293
|
-
await db.execute(`ALTER TABLE service_connection_action_audit ADD COLUMN result_json TEXT`);
|
|
81294
|
-
} catch {
|
|
81295
|
-
}
|
|
81296
|
-
})().catch((error) => {
|
|
81297
|
-
schemaReady3 = null;
|
|
81298
|
-
schemaDb6 = null;
|
|
81299
|
-
throw error;
|
|
81300
|
-
});
|
|
81301
|
-
return schemaReady3;
|
|
81302
|
-
}
|
|
81303
|
-
function parseTools(value) {
|
|
81304
|
-
if (typeof value !== "string") return [];
|
|
81305
|
-
try {
|
|
81306
|
-
const parsed = JSON.parse(value);
|
|
81307
|
-
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
81308
|
-
} catch {
|
|
81309
|
-
return [];
|
|
81310
|
-
}
|
|
81311
|
-
}
|
|
81312
|
-
function rowToRecord(row) {
|
|
81313
|
-
return {
|
|
81314
|
-
id: String(row.id),
|
|
81315
|
-
userId: Number(row.user_id),
|
|
81316
|
-
providerConfigKey: String(row.provider_config_key),
|
|
81317
|
-
provider: typeof row.provider === "string" ? row.provider : null,
|
|
81318
|
-
transport: row.transport === "remote_mcp" ? "remote_mcp" : "nango",
|
|
81319
|
-
upstreamConnectionId: typeof row.upstream_connection_id === "string" ? row.upstream_connection_id : null,
|
|
81320
|
-
label: typeof row.label === "string" ? row.label : null,
|
|
81321
|
-
userLabel: typeof row.user_label === "string" ? row.user_label : null,
|
|
81322
|
-
providerAccountId: typeof row.provider_account_id === "string" ? row.provider_account_id : null,
|
|
81323
|
-
providerAccountEmail: typeof row.provider_account_email === "string" ? row.provider_account_email : null,
|
|
81324
|
-
providerAccountName: typeof row.provider_account_name === "string" ? row.provider_account_name : null,
|
|
81325
|
-
providerIdentityCheckedAt: typeof row.provider_identity_checked_at === "string" ? row.provider_identity_checked_at : null,
|
|
81326
|
-
providerIdentitySourceUpdatedAt: typeof row.provider_identity_source_updated_at === "string" ? row.provider_identity_source_updated_at : null,
|
|
81327
|
-
lifecycleStatus: String(row.lifecycle_status),
|
|
81328
|
-
operationalStatus: String(row.operational_status),
|
|
81329
|
-
reconnectRequired: Number(row.reconnect_required) === 1,
|
|
81330
|
-
actionsEnabled: Number(row.actions_enabled) === 1,
|
|
81331
|
-
readTools: parseTools(row.read_tools_json),
|
|
81332
|
-
actionTools: parseTools(row.action_tools_json),
|
|
81333
|
-
toolRevision: typeof row.tool_revision === "string" ? row.tool_revision : null,
|
|
81334
|
-
lastCheckedAt: typeof row.last_checked_at === "string" ? row.last_checked_at : null,
|
|
81335
|
-
lastSuccessfulCallAt: typeof row.last_successful_call_at === "string" ? row.last_successful_call_at : null,
|
|
81336
|
-
lastFailureAt: typeof row.last_failure_at === "string" ? row.last_failure_at : null,
|
|
81337
|
-
lastFailureCode: typeof row.last_failure_code === "string" ? row.last_failure_code : null,
|
|
81338
|
-
lastFailureRetryable: row.last_failure_retryable === null || row.last_failure_retryable === void 0 ? null : Number(row.last_failure_retryable) === 1,
|
|
81339
|
-
consecutiveFailures: Number(row.consecutive_failures ?? 0),
|
|
81340
|
-
vaultName: typeof row.vault_name === "string" ? row.vault_name : null,
|
|
81341
|
-
tableName: typeof row.table_name === "string" ? row.table_name : null,
|
|
81342
|
-
createdAt: String(row.created_at),
|
|
81343
|
-
updatedAt: String(row.updated_at)
|
|
81344
|
-
};
|
|
81345
|
-
}
|
|
81346
|
-
async function userIdForIdentity(identity) {
|
|
81347
|
-
const user = await getUserByEmail(identity.normalize("NFKC").trim().toLowerCase());
|
|
81348
|
-
if (!user) throw new Error("service_connection_user_not_found");
|
|
81349
|
-
return Number(user.id);
|
|
81350
|
-
}
|
|
81351
|
-
async function reconcileDiscoveredNangoConnections(identity, discovered) {
|
|
81352
|
-
await ensureServiceConnectionsSchema();
|
|
81353
|
-
const db = getDb();
|
|
81354
|
-
const userId = await userIdForIdentity(identity);
|
|
81355
|
-
for (const connection of discovered) {
|
|
81356
|
-
await db.execute({
|
|
81357
|
-
sql: `
|
|
81358
|
-
INSERT INTO service_connections (
|
|
81359
|
-
id, user_id, provider_config_key, provider, transport, upstream_connection_id,
|
|
81360
|
-
label, lifecycle_status, reconnect_required, actions_enabled, legacy_owner_identity, created_at, updated_at
|
|
81361
|
-
) VALUES (?, ?, ?, ?, 'nango', ?, ?, ?, ?, 1, ?, COALESCE(?, datetime('now')), COALESCE(?, datetime('now')))
|
|
81362
|
-
ON CONFLICT(user_id, provider_config_key, upstream_connection_id) DO UPDATE SET
|
|
81363
|
-
provider = excluded.provider,
|
|
81364
|
-
label = COALESCE(excluded.label, service_connections.label),
|
|
81365
|
-
lifecycle_status = excluded.lifecycle_status,
|
|
81366
|
-
reconnect_required = excluded.reconnect_required,
|
|
81367
|
-
updated_at = excluded.updated_at
|
|
81368
|
-
`,
|
|
81369
|
-
args: [
|
|
81370
|
-
(0, import_node_crypto59.randomUUID)(),
|
|
81371
|
-
userId,
|
|
81372
|
-
connection.providerConfigKey,
|
|
81373
|
-
connection.provider,
|
|
81374
|
-
connection.upstreamConnectionId,
|
|
81375
|
-
connection.label,
|
|
81376
|
-
connection.lifecycleStatus,
|
|
81377
|
-
connection.reconnectRequired ? 1 : 0,
|
|
81378
|
-
identity,
|
|
81379
|
-
connection.createdAt,
|
|
81380
|
-
connection.updatedAt
|
|
81381
|
-
]
|
|
81382
|
-
});
|
|
81383
|
-
}
|
|
81384
|
-
return listServiceConnections(identity, "nango");
|
|
81385
|
-
}
|
|
81386
|
-
async function listServiceConnections(identity, transport) {
|
|
81387
|
-
await ensureServiceConnectionsSchema();
|
|
81388
|
-
const userId = await userIdForIdentity(identity);
|
|
81389
|
-
const result = await getDb().execute({
|
|
81390
|
-
sql: `SELECT * FROM service_connections WHERE user_id = ?${transport ? " AND transport = ?" : ""} AND lifecycle_status <> 'disconnected' ORDER BY updated_at DESC`,
|
|
81391
|
-
args: transport ? [userId, transport] : [userId]
|
|
81392
|
-
});
|
|
81393
|
-
return result.rows.map((row) => rowToRecord(row));
|
|
81394
|
-
}
|
|
81395
|
-
async function getOwnedServiceConnection(identity, connectionId) {
|
|
81396
|
-
await ensureServiceConnectionsSchema();
|
|
81397
|
-
const userId = await userIdForIdentity(identity);
|
|
81398
|
-
const result = await getDb().execute({
|
|
81399
|
-
sql: "SELECT * FROM service_connections WHERE id = ? AND user_id = ? LIMIT 1",
|
|
81400
|
-
args: [connectionId, userId]
|
|
81401
|
-
});
|
|
81402
|
-
const row = result.rows[0];
|
|
81403
|
-
return row ? rowToRecord(row) : null;
|
|
81404
|
-
}
|
|
81405
|
-
async function updateServiceConnectionTools(connectionId, readTools, actionTools, toolRevision) {
|
|
81406
|
-
await ensureServiceConnectionsSchema();
|
|
81407
|
-
await getDb().execute({
|
|
81408
|
-
sql: `UPDATE service_connections SET read_tools_json = ?, action_tools_json = ?, tool_revision = ?, updated_at = datetime('now') WHERE id = ?`,
|
|
81409
|
-
args: [JSON.stringify(readTools), JSON.stringify(actionTools), toolRevision, connectionId]
|
|
81410
|
-
});
|
|
81411
|
-
}
|
|
81412
|
-
async function setServiceConnectionProviderIdentity(args) {
|
|
81413
|
-
await ensureServiceConnectionsSchema();
|
|
81414
|
-
await getDb().execute({
|
|
81415
|
-
sql: `
|
|
81416
|
-
UPDATE service_connections SET
|
|
81417
|
-
provider_account_id = ?, provider_account_email = ?, provider_account_name = ?,
|
|
81418
|
-
provider_identity_checked_at = datetime('now'), provider_identity_source_updated_at = ?,
|
|
81419
|
-
updated_at = datetime('now')
|
|
81420
|
-
WHERE id = ?
|
|
81421
|
-
`,
|
|
81422
|
-
args: [
|
|
81423
|
-
args.providerAccountId ?? null,
|
|
81424
|
-
args.providerAccountEmail?.toLowerCase() ?? null,
|
|
81425
|
-
args.providerAccountName ?? null,
|
|
81426
|
-
args.sourceUpdatedAt,
|
|
81427
|
-
args.connectionId
|
|
81428
|
-
]
|
|
81429
|
-
});
|
|
81430
|
-
}
|
|
81431
|
-
async function setServiceConnectionUserLabel(identity, connectionId, userLabel) {
|
|
81432
|
-
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
81433
|
-
if (!connection || connection.lifecycleStatus === "disconnected") throw new Error("service_connection_not_found");
|
|
81434
|
-
await getDb().execute({
|
|
81435
|
-
sql: `UPDATE service_connections SET user_label = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
81436
|
-
args: [userLabel, connectionId, connection.userId]
|
|
81437
|
-
});
|
|
81438
|
-
return userLabel;
|
|
81439
|
-
}
|
|
81440
|
-
async function recordServiceConnectionHealth(args) {
|
|
81441
|
-
await ensureServiceConnectionsSchema();
|
|
81442
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
81443
|
-
await getDb().execute({
|
|
81444
|
-
sql: `
|
|
81445
|
-
UPDATE service_connections SET
|
|
81446
|
-
operational_status = ?, last_checked_at = ?,
|
|
81447
|
-
last_successful_call_at = CASE WHEN ? = 'available' THEN ? ELSE last_successful_call_at END,
|
|
81448
|
-
last_failure_at = CASE WHEN ? IN ('degraded', 'unavailable') THEN ? ELSE NULL END,
|
|
81449
|
-
last_failure_code = ?, last_failure_retryable = ?,
|
|
81450
|
-
consecutive_failures = CASE WHEN ? = 'available' THEN 0 ELSE consecutive_failures + 1 END,
|
|
81451
|
-
updated_at = datetime('now')
|
|
81452
|
-
WHERE id = ?
|
|
81453
|
-
`,
|
|
81454
|
-
args: [
|
|
81455
|
-
args.operationalStatus,
|
|
81456
|
-
now,
|
|
81457
|
-
args.operationalStatus,
|
|
81458
|
-
now,
|
|
81459
|
-
args.operationalStatus,
|
|
81460
|
-
now,
|
|
81461
|
-
args.failureCode ?? null,
|
|
81462
|
-
args.retryable == null ? null : args.retryable ? 1 : 0,
|
|
81463
|
-
args.operationalStatus,
|
|
81464
|
-
args.connectionId
|
|
81465
|
-
]
|
|
81466
|
-
});
|
|
81467
|
-
await getDb().execute({
|
|
81468
|
-
sql: `INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
81469
|
-
args: [(0, import_node_crypto59.randomUUID)(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
|
|
81470
|
-
});
|
|
81471
|
-
}
|
|
81472
|
-
async function setServiceConnectionActions(identity, connectionId, enabled) {
|
|
81473
|
-
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
81474
|
-
if (!connection || connection.lifecycleStatus === "disconnected") throw new Error("service_connection_not_found");
|
|
81475
|
-
await getDb().execute({
|
|
81476
|
-
sql: `UPDATE service_connections SET actions_enabled = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
81477
|
-
args: [enabled ? 1 : 0, connectionId, connection.userId]
|
|
81478
|
-
});
|
|
81479
|
-
return enabled;
|
|
81480
|
-
}
|
|
81481
|
-
async function markServiceConnectionDisconnected(identity, connectionId) {
|
|
81482
|
-
const connection = await getOwnedServiceConnection(identity, connectionId);
|
|
81483
|
-
if (!connection) throw new Error("service_connection_not_found");
|
|
81484
|
-
await getDb().execute({
|
|
81485
|
-
sql: `UPDATE service_connections SET lifecycle_status = 'disconnected', operational_status = 'unknown', reconnect_required = 0, updated_at = datetime('now') WHERE id = ? AND user_id = ?`,
|
|
81486
|
-
args: [connectionId, connection.userId]
|
|
81487
|
-
});
|
|
81488
|
-
const remaining = await getDb().execute({
|
|
81489
|
-
sql: `SELECT COUNT(*) AS count FROM service_connections WHERE user_id = ? AND transport = 'nango' AND lifecycle_status = 'connected'`,
|
|
81490
|
-
args: [connection.userId]
|
|
81491
|
-
});
|
|
81492
|
-
return Number(remaining.rows[0]?.count ?? 0);
|
|
81493
|
-
}
|
|
81494
|
-
async function recordServiceConnectionAction(args) {
|
|
81495
|
-
await ensureServiceConnectionsSchema();
|
|
81496
|
-
const connection = await getOwnedServiceConnection(args.identity, args.connectionId);
|
|
81497
|
-
if (!connection) throw new Error("service_connection_not_found");
|
|
81498
|
-
await getDb().execute({
|
|
81499
|
-
sql: `UPDATE service_connection_action_audit SET status = ?, error_code = ?, result_json = ? WHERE user_id = ? AND request_id = ? AND connection_id = ?`,
|
|
81500
|
-
args: [args.status, args.errorCode ?? null, args.result === void 0 ? null : JSON.stringify(args.result), connection.userId, args.requestId, connection.id]
|
|
81501
|
-
});
|
|
81502
|
-
}
|
|
81503
|
-
async function claimServiceConnectionAction(args) {
|
|
81504
|
-
await ensureServiceConnectionsSchema();
|
|
81505
|
-
const connection = await getOwnedServiceConnection(args.identity, args.connectionId);
|
|
81506
|
-
if (!connection) throw new Error("service_connection_not_found");
|
|
81507
|
-
const inserted = await getDb().execute({
|
|
81508
|
-
sql: `INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)`,
|
|
81509
|
-
args: [(0, import_node_crypto59.randomUUID)(), connection.id, connection.userId, args.tool, args.requestId, args.requestDigest]
|
|
81510
|
-
});
|
|
81511
|
-
if (Number(inserted.rowsAffected ?? 0) === 1) return { claimed: true };
|
|
81512
|
-
const existing = await getDb().execute({
|
|
81513
|
-
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`,
|
|
81514
|
-
args: [connection.userId, args.requestId]
|
|
81515
|
-
});
|
|
81516
|
-
const row = existing.rows[0];
|
|
81517
|
-
const conflict = String(row?.connection_id ?? "") !== connection.id || String(row?.tool ?? "") !== args.tool || String(row?.request_digest ?? "") !== args.requestDigest;
|
|
81518
|
-
let result = void 0;
|
|
81519
|
-
if (!conflict && typeof row?.result_json === "string") {
|
|
81520
|
-
try {
|
|
81521
|
-
result = JSON.parse(row.result_json);
|
|
81522
|
-
} catch {
|
|
81523
|
-
result = void 0;
|
|
81524
|
-
}
|
|
81525
|
-
}
|
|
81526
|
-
return {
|
|
81527
|
-
claimed: false,
|
|
81528
|
-
status: String(row?.status ?? "unknown"),
|
|
81529
|
-
errorCode: typeof row?.error_code === "string" ? row.error_code : null,
|
|
81530
|
-
conflict,
|
|
81531
|
-
...result !== void 0 ? { result } : {}
|
|
81532
|
-
};
|
|
81533
|
-
}
|
|
81534
|
-
var import_node_crypto59, schemaReady3, schemaDb6;
|
|
81535
|
-
var init_service_connections = __esm({
|
|
81536
|
-
"src/api/service-connections.ts"() {
|
|
81537
|
-
"use strict";
|
|
81538
|
-
import_node_crypto59 = require("crypto");
|
|
81539
|
-
init_db();
|
|
81540
|
-
schemaReady3 = null;
|
|
81541
|
-
schemaDb6 = null;
|
|
81542
|
-
}
|
|
81543
|
-
});
|
|
81544
|
-
|
|
81545
81837
|
// src/api/scheduler-integration-auth.ts
|
|
81546
81838
|
function signingSecret() {
|
|
81547
81839
|
const secret2 = process.env.SCHEDULER_INTEGRATION_SIGNING_SECRET?.trim();
|