mcp-scraper 0.88.2 → 0.89.1
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 +41 -2
- package/README.md +6 -3
- package/dist/analytics-repository-J25XR5E7.js +1 -0
- package/dist/bin/api-server.js +2 -41
- package/dist/bin/mcp-scraper-cli.js +39 -756
- package/dist/bin/mcp-scraper-core.js +1 -60
- package/dist/bin/mcp-scraper-install.js +2 -25
- package/dist/bin/mcp-stdio-server.js +1 -19
- package/dist/bin/paa-harvest.js +1 -41
- package/dist/chunk-3GP5CYZX.js +1 -0
- package/dist/chunk-4FROKQJN.js +1 -0
- package/dist/chunk-57AHYL2O.js +20 -0
- package/dist/chunk-5H3MCTTP.js +1 -0
- package/dist/chunk-63T4W2LX.js +1271 -0
- package/dist/chunk-645LQBE7.js +2595 -0
- package/dist/chunk-6QO4F2KC.js +21710 -0
- package/dist/chunk-CCYWSJNG.js +16 -0
- package/dist/chunk-D6IQJP64.js +84 -0
- package/dist/chunk-DGBLGFNJ.js +182 -0
- package/dist/chunk-FFPD2DOF.js +59 -0
- package/dist/chunk-FXEWHK54.js +1 -0
- package/dist/chunk-HE45FFBU.js +1 -0
- package/dist/chunk-HUV2WTRW.js +1 -0
- package/dist/chunk-IJ2AO7AO.js +102 -0
- package/dist/chunk-KJQXUZ4Y.js +4 -0
- package/dist/chunk-MEM4D2QN.js +1280 -0
- package/dist/chunk-MZN4U5BL.js +1 -0
- package/dist/chunk-PRWZNHQB.js +1 -0
- package/dist/chunk-QPWPR5XG.js +10 -0
- package/dist/chunk-RYNHNEF3.js +73 -0
- package/dist/chunk-TMB56NCA.js +1 -0
- package/dist/chunk-W2BVJ7S2.js +13 -0
- package/dist/chunk-WO3N5FH2.js +5 -0
- package/dist/chunk-XLWNEVUZ.js +27 -0
- package/dist/chunk-YQZGZBB4.js +1 -0
- package/dist/chunk-YUPLOOTB.js +4 -0
- package/dist/chunk-ZHORX44A.js +100 -0
- package/dist/db-JJWJLAVQ.js +1 -0
- package/dist/extract-bundle-TTSEGWYF.js +26 -0
- package/dist/gmail-service-34PIJRLK.js +1 -0
- package/dist/index.cjs +21838 -6034
- package/dist/index.js +18 -315
- package/dist/lead-list-enrichment-repository-VJBBMBCG.js +1 -0
- package/dist/location-data-repository-W3LPT6G3.js +1 -0
- package/dist/server-UEY5YQL6.js +7329 -0
- package/dist/site-extract-repository-7W5ZUNPR.js +1 -0
- package/dist/worker-ZOTOKG56.js +1 -0
- package/package.json +11 -4
- package/dist/analytics-repository-GGJJCVVP.js +0 -194
- package/dist/chunk-4QMUF6XM.js +0 -1013
- package/dist/chunk-6HAV7LCE.js +0 -265
- package/dist/chunk-ABF2CGOZ.js +0 -113
- package/dist/chunk-C5Z4OFKW.js +0 -404
- package/dist/chunk-DNM65UCK.js +0 -299
- package/dist/chunk-EQGTEHLZ.js +0 -592
- package/dist/chunk-F5GQJWZU.js +0 -732
- package/dist/chunk-GGZEC22A.js +0 -215
- package/dist/chunk-GXBZXWXB.js +0 -184
- package/dist/chunk-IHXAXYIS.js +0 -843
- package/dist/chunk-K3Z5AQYE.js +0 -683
- package/dist/chunk-K45K75OF.js +0 -6
- package/dist/chunk-LFW2FRPJ.js +0 -224
- package/dist/chunk-MZDNZQWT.js +0 -2078
- package/dist/chunk-NVUKO5NN.js +0 -256
- package/dist/chunk-OM7HVEJ3.js +0 -26
- package/dist/chunk-OPQIGAFB.js +0 -286
- package/dist/chunk-OZJMVCDK.js +0 -16
- package/dist/chunk-P7FWOMU7.js +0 -505
- package/dist/chunk-PGJQDMC2.js +0 -383
- package/dist/chunk-PKZS6SHW.js +0 -33139
- package/dist/chunk-RJ7JVYKU.js +0 -68
- package/dist/chunk-S24LFPL7.js +0 -5262
- package/dist/chunk-T3MZISOF.js +0 -240
- package/dist/chunk-UZPTGUDV.js +0 -1915
- package/dist/chunk-X623GTBV.js +0 -8290
- package/dist/chunk-YXNDOQXN.js +0 -4018
- package/dist/db-Z34LPZNR.js +0 -284
- package/dist/extract-bundle-565SBZCR.js +0 -1003
- package/dist/gmail-service-E6ALS7JG.js +0 -25
- package/dist/lead-list-enrichment-repository-36RPVV6N.js +0 -67
- package/dist/location-data-repository-WPRG62GE.js +0 -34
- package/dist/server-SQZ3A7SY.js +0 -86606
- package/dist/site-extract-repository-VYFZASPU.js +0 -69
- package/dist/worker-LDCAULWL.js +0 -146
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
var s={message:"Discover public Facebook Reel URLs, retain partial inventories, and transcribe selected videos. Facebook extraction now dismisses optional login dialogs and retries failed public acquisition."};var _={reset:"\x1B[0m",cyan:"\x1B[36m",lime:"\x1B[32m",amber:"\x1B[33m",red:"\x1B[31m",muted:"\x1B[90m",bold:"\x1B[1m"};function r(t,e,n){return n?`${_[e]}${t}${_.reset}`:t}function o(t,e,n){let a=t.padEnd(9," ");return` ${r(a,"muted",n)} ${e.join(r(" . ","muted",n))}`}function p(t){let e=t.color??!0,n=t.apiKeyConfigured?"$MCP_SCRAPER_API_KEY":"sk_live_your_key",a=String.raw`
|
|
2
|
+
__ __ ____ ____
|
|
3
|
+
| \/ |/ ___| _ \
|
|
4
|
+
| |\/| | | | |_) |
|
|
5
|
+
| | | | |___| __/
|
|
6
|
+
|_| |_|\____|_|
|
|
7
|
+
|
|
8
|
+
____ ____ ____ _ ____ _____ ____
|
|
9
|
+
/ ___| / ___| _ \ / \ | _ \| ____| _ \
|
|
10
|
+
\___ \| | | |_) | / _ \ | |_) | _| | |_) |
|
|
11
|
+
___) | |___| _ < / ___ \| __/| |___| _ <
|
|
12
|
+
|____/ \____|_| \_\/_/ \_\_| |_____|_| \_\
|
|
13
|
+
`,i=[`MCP_SCRAPER_API_KEY=${n} npx -y -p mcp-scraper@latest \\`," mcp-scraper-cli agent install claude --apply"].join(`
|
|
14
|
+
`),c=["[mcp_servers.mcp-scraper]",'command = "npx"','args = ["-y", "-p", "mcp-scraper@latest", "mcp-scraper"]',`env = { MCP_SCRAPER_API_KEY = "${n}" }`].join(`
|
|
15
|
+
`);return[r(`mcp-scraper v${t.version}`,"bold",e),r("> mcp-scraper-install","muted",e),r(a,"amber",e),`${r("MCP Scraper Agent","cyan",e)} . v${t.version} . mcpscraper.dev`,"1/1 install surfaces ready",r(`Newest in v${t.version}: ${s.message}`,"lime",e),"",`${r("Tools","cyan",e)} ${r("(376 MCP tools)","muted",e)}`,o("search",["harvest_paa","search_serp","maps_search","maps_place_intel"],e),o("extract",["extract_url","map_site_urls","extract_site","audit_site","directory_workflow"],e),o("build",["create_editorial_reading_room","rank_tracker_workflow","portable HTML"],e),o("media",["youtube_harvest","youtube_transcribe","facebook_reels_inventory","facebook_ad_search","facebook_page_intel","facebook_ad_transcribe","facebook_video_transcribe","instagram_profile_content","instagram_media_download","reddit_thread"],e),o("browser",["serp_identity_create","serp_identity_list","browser_open","browser_profile_connect","browser_profile_list","browser_close","browser_screenshot","browser_read","browser_locate","browser_replay_mark","browser_replay_annotate"],e),o("connect",["list_service_connections","describe_service_connection_tool","import_service_connection_to_memory","export_connected_service_data","renew_connected_data_download","read_service_connection","call_service_connection_action"],e),o("commons",["commons_search_entities","commons_get_entity_linkset","commons_prepare_entity","commons_submit_entity","commons_prepare_publication","commons_claim_publication","commons_publish_editorial","commons_get_publication"],e),o("account",["credits_info","reports","MCP resources"],e),o("memory",["memory-put","memory-get","memory-search","list-vaults","record-fact","list-scheduled-actions"],e),`${r("Workflows","cyan",e)} ${r("(MCP + CLI + API)","muted",e)}`,o("route",["workflow_list","workflow_suggest","workflow_run","workflow_step","workflow_status","workflow_artifact_read"],e),o("seo",["directory","agent-packet","competitive audit","map/serp comparison","PAA/AIO briefs","scheduled runs"],e),"",r("Usage tips:","amber",e),"Run mcp-scraper-install for this visible card. Run mcp-scraper-cli for setup utilities and subcommands.","Run mcp-scraper in a human terminal to print this card; MCP clients get the same command as a silent stdio server.","Explicit card command: npx -y -p mcp-scraper@latest mcp-scraper-install","Hosted browser sessions use direct/no-proxy egress by default.","Customer auth setup: run browser_profile_connect, send the watch_url, let the user sign in, then call browser_profile_list until AUTHENTICATED.","Connected account ranges: call export_connected_service_data once. It handles Gmail, Calendar, Zoom, and Resend pagination; do not loop read_service_connection over individual records.","Connected account RAG: call import_service_connection_to_memory for one bounded approved read. It writes a redacted, untrusted snapshot to a stable Memory path and embeds it for search.","Stack logins / reconnect: run browser_profile_connect again with the same profile name and another domain to add accounts or refresh a login.","Start with workflow_suggest for broad jobs like market analysis, ICP research, CRO audits, brand briefs, content gaps, and AI visibility.","For MCP clients, use mcp-scraper so one install can mix SERP, Maps, browser, reports, and saved MCP resources.","If you hit the concurrency limit, add 2 browsers for $5/month with mcp-scraper-cli billing concurrency checkout.","",`${r("Ready.","lime",e)} Install the combined MCP server with one command:`,"",r("Setup doctor","amber",e),"npx -y -p mcp-scraper@latest mcp-scraper-cli doctor","",r("Hosted profile setup","amber",e),'In your MCP client, call browser_profile_connect with email="seo@example.com" and domain="chatgpt.com".',"Give the returned watch_url to the user. After they sign in, call browser_profile_list, then browser_open with the returned profile. Add more logins by calling browser_profile_connect again with the same profile and a new domain.","",r("Claude Code one-command setup","amber",e),i,"Then fully exit Claude Code and open a new Claude terminal. Check with: claude mcp list","",r("Codex config","amber",e),c,"",r("Claude Desktop Extension","amber",e),"Download: https://mcpscraper.dev/downloads/mcp-scraper.mcpb","",r("Safety note:","muted",e),"mcp-scraper prints this card only when stdin/stdout are an interactive TTY. In MCP clients it writes only JSON-RPC to stdout.","Use --stdio or MCP_SCRAPER_FORCE_STDIO=1 to force server mode from a terminal.",""].join(`
|
|
16
|
+
`)}export{p as a};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import{M as p,s as o}from"./chunk-63T4W2LX.js";import{createHmac as T,timingSafeEqual as y}from"crypto";var N=()=>process.env.NODE_ENV==="production"||process.env.VERCEL==="1";function S(){let e=process.env.SESSION_SECRET?.trim();if(e)return e;if(N())throw new Error("SESSION_SECRET is not set \u2014 add it to your Vercel env vars (see src/api/env.ts)");return"dev-secret-change-me"}var v=()=>S();function m(e,t){if(e.length!==t.length)return!1;try{return y(Buffer.from(e,"hex"),Buffer.from(t,"hex"))}catch{return!1}}function L(e){let t=String(e),n=T("sha256",v()).update(t).digest("hex");return`${t}.${n}`}function I(e){let t=e.lastIndexOf(".");if(t===-1)return null;let n=e.slice(0,t),r=e.slice(t+1),i=T("sha256",v()).update(n).digest("hex");if(!m(r,i))return null;let s=parseInt(n);return isNaN(s)?null:s}import{randomUUID as _}from"crypto";function x(e,t,n){return e.lifecycleStatus==="connected"&&e.actionsEnabled&&t.includes(e.providerConfigKey)&&e.actionTools.includes(n)}var a=null,u=null;function c(){let e=o();return a&&u===e||(u=e,a=(async()=>{let t=e;await t.execute(`
|
|
2
|
+
CREATE TABLE IF NOT EXISTS service_connections (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
5
|
+
provider_config_key TEXT NOT NULL,
|
|
6
|
+
provider TEXT,
|
|
7
|
+
transport TEXT NOT NULL,
|
|
8
|
+
upstream_connection_id TEXT,
|
|
9
|
+
label TEXT,
|
|
10
|
+
user_label TEXT,
|
|
11
|
+
provider_account_id TEXT,
|
|
12
|
+
provider_account_email TEXT,
|
|
13
|
+
provider_account_name TEXT,
|
|
14
|
+
provider_identity_checked_at TEXT,
|
|
15
|
+
provider_identity_source_updated_at TEXT,
|
|
16
|
+
lifecycle_status TEXT NOT NULL DEFAULT 'pending',
|
|
17
|
+
operational_status TEXT NOT NULL DEFAULT 'unknown',
|
|
18
|
+
reconnect_required INTEGER NOT NULL DEFAULT 0,
|
|
19
|
+
actions_enabled INTEGER NOT NULL DEFAULT 0,
|
|
20
|
+
read_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
21
|
+
action_tools_json TEXT NOT NULL DEFAULT '[]',
|
|
22
|
+
tool_revision TEXT,
|
|
23
|
+
last_checked_at TEXT,
|
|
24
|
+
last_successful_call_at TEXT,
|
|
25
|
+
last_failure_at TEXT,
|
|
26
|
+
last_failure_code TEXT,
|
|
27
|
+
last_failure_retryable INTEGER,
|
|
28
|
+
consecutive_failures INTEGER NOT NULL DEFAULT 0,
|
|
29
|
+
vault_name TEXT,
|
|
30
|
+
table_name TEXT,
|
|
31
|
+
legacy_owner_identity TEXT,
|
|
32
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
33
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
34
|
+
UNIQUE(user_id, provider_config_key, upstream_connection_id)
|
|
35
|
+
)
|
|
36
|
+
`);try{await t.execute("ALTER TABLE service_connections ADD COLUMN user_label TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_account_id TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_account_email TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_account_name TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_identity_checked_at TEXT")}catch{}try{await t.execute("ALTER TABLE service_connections ADD COLUMN provider_identity_source_updated_at TEXT")}catch{}await t.execute("CREATE INDEX IF NOT EXISTS service_connections_user_updated ON service_connections(user_id, updated_at DESC)"),await t.execute("CREATE INDEX IF NOT EXISTS service_connections_upstream ON service_connections(provider_config_key, upstream_connection_id)"),await t.execute(`
|
|
37
|
+
CREATE TABLE IF NOT EXISTS service_connection_health_events (
|
|
38
|
+
id TEXT PRIMARY KEY,
|
|
39
|
+
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
40
|
+
operational_status TEXT NOT NULL,
|
|
41
|
+
failure_code TEXT,
|
|
42
|
+
retryable INTEGER,
|
|
43
|
+
evidence_source TEXT NOT NULL,
|
|
44
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
45
|
+
)
|
|
46
|
+
`),await t.execute("CREATE INDEX IF NOT EXISTS service_connection_health_events_connection ON service_connection_health_events(connection_id, created_at DESC)"),await t.execute(`
|
|
47
|
+
CREATE TABLE IF NOT EXISTS service_connection_action_audit (
|
|
48
|
+
id TEXT PRIMARY KEY,
|
|
49
|
+
connection_id TEXT NOT NULL REFERENCES service_connections(id) ON DELETE CASCADE,
|
|
50
|
+
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
51
|
+
tool TEXT NOT NULL,
|
|
52
|
+
request_id TEXT NOT NULL,
|
|
53
|
+
status TEXT NOT NULL,
|
|
54
|
+
error_code TEXT,
|
|
55
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
56
|
+
UNIQUE(user_id, request_id)
|
|
57
|
+
)
|
|
58
|
+
`);try{await t.execute("ALTER TABLE service_connection_action_audit ADD COLUMN request_digest TEXT")}catch{}try{await t.execute("ALTER TABLE service_connection_action_audit ADD COLUMN result_json TEXT")}catch{}})().catch(t=>{throw a=null,u=null,t})),a}function f(e){if(typeof e!="string")return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(n=>typeof n=="string"):[]}catch{return[]}}function g(e){return{id:String(e.id),userId:Number(e.user_id),providerConfigKey:String(e.provider_config_key),provider:typeof e.provider=="string"?e.provider:null,transport:e.transport==="remote_mcp"?"remote_mcp":e.transport==="credential_reference"?"credential_reference":"nango",upstreamConnectionId:typeof e.upstream_connection_id=="string"?e.upstream_connection_id:null,label:typeof e.label=="string"?e.label:null,userLabel:typeof e.user_label=="string"?e.user_label:null,providerAccountId:typeof e.provider_account_id=="string"?e.provider_account_id:null,providerAccountEmail:typeof e.provider_account_email=="string"?e.provider_account_email:null,providerAccountName:typeof e.provider_account_name=="string"?e.provider_account_name:null,providerIdentityCheckedAt:typeof e.provider_identity_checked_at=="string"?e.provider_identity_checked_at:null,providerIdentitySourceUpdatedAt:typeof e.provider_identity_source_updated_at=="string"?e.provider_identity_source_updated_at:null,lifecycleStatus:String(e.lifecycle_status),operationalStatus:String(e.operational_status),reconnectRequired:Number(e.reconnect_required)===1,actionsEnabled:Number(e.actions_enabled)===1,readTools:f(e.read_tools_json),actionTools:f(e.action_tools_json),toolRevision:typeof e.tool_revision=="string"?e.tool_revision:null,lastCheckedAt:typeof e.last_checked_at=="string"?e.last_checked_at:null,lastSuccessfulCallAt:typeof e.last_successful_call_at=="string"?e.last_successful_call_at:null,lastFailureAt:typeof e.last_failure_at=="string"?e.last_failure_at:null,lastFailureCode:typeof e.last_failure_code=="string"?e.last_failure_code:null,lastFailureRetryable:e.last_failure_retryable===null||e.last_failure_retryable===void 0?null:Number(e.last_failure_retryable)===1,consecutiveFailures:Number(e.consecutive_failures??0),vaultName:typeof e.vault_name=="string"?e.vault_name:null,tableName:typeof e.table_name=="string"?e.table_name:null,createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}async function E(e){let t=await p(e.normalize("NFKC").trim().toLowerCase());if(!t)throw new Error("service_connection_user_not_found");return Number(t.id)}async function D(e,t){await c();let n=o(),r=await E(e);for(let i of t)await n.execute({sql:`
|
|
59
|
+
INSERT INTO service_connections (
|
|
60
|
+
id, user_id, provider_config_key, provider, transport, upstream_connection_id,
|
|
61
|
+
label, lifecycle_status, reconnect_required, actions_enabled, legacy_owner_identity, created_at, updated_at
|
|
62
|
+
) VALUES (?, ?, ?, ?, 'nango', ?, ?, ?, ?, 1, ?, COALESCE(?, datetime('now')), COALESCE(?, datetime('now')))
|
|
63
|
+
ON CONFLICT(user_id, provider_config_key, upstream_connection_id) DO UPDATE SET
|
|
64
|
+
provider = excluded.provider,
|
|
65
|
+
label = COALESCE(excluded.label, service_connections.label),
|
|
66
|
+
lifecycle_status = excluded.lifecycle_status,
|
|
67
|
+
reconnect_required = excluded.reconnect_required,
|
|
68
|
+
updated_at = excluded.updated_at
|
|
69
|
+
`,args:[_(),r,i.providerConfigKey,i.provider,i.upstreamConnectionId,i.label,i.lifecycleStatus,i.reconnectRequired?1:0,e,i.createdAt,i.updatedAt]});return A(e,"nango")}async function A(e,t){await c();let n=await E(e);return(await o().execute({sql:`SELECT * FROM service_connections WHERE user_id = ?${t?" AND transport = ?":""} AND lifecycle_status <> 'disconnected' ORDER BY updated_at DESC`,args:t?[n,t]:[n]})).rows.map(i=>g(i))}async function d(e,t){await c();let n=await E(e),i=(await o().execute({sql:"SELECT * FROM service_connections WHERE id = ? AND user_id = ? LIMIT 1",args:[t,n]})).rows[0];return i?g(i):null}async function w(e,t,n,r){await c(),await o().execute({sql:"UPDATE service_connections SET read_tools_json = ?, action_tools_json = ?, tool_revision = ?, updated_at = datetime('now') WHERE id = ?",args:[JSON.stringify(t),JSON.stringify(n),r,e]})}async function U(e){await c(),await o().execute({sql:`
|
|
70
|
+
UPDATE service_connections SET
|
|
71
|
+
provider_account_id = ?, provider_account_email = ?, provider_account_name = ?,
|
|
72
|
+
provider_identity_checked_at = datetime('now'), provider_identity_source_updated_at = ?,
|
|
73
|
+
updated_at = datetime('now')
|
|
74
|
+
WHERE id = ?
|
|
75
|
+
`,args:[e.providerAccountId??null,e.providerAccountEmail?.toLowerCase()??null,e.providerAccountName??null,e.sourceUpdatedAt,e.connectionId]})}async function h(e,t,n){let r=await d(e,t);if(!r||r.lifecycleStatus==="disconnected")throw new Error("service_connection_not_found");return await o().execute({sql:"UPDATE service_connections SET user_label = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?",args:[n,t,r.userId]}),n}async function X(e){await c();let t=new Date().toISOString();await o().execute({sql:`
|
|
76
|
+
UPDATE service_connections SET
|
|
77
|
+
operational_status = ?, last_checked_at = ?,
|
|
78
|
+
last_successful_call_at = CASE WHEN ? = 'available' THEN ? ELSE last_successful_call_at END,
|
|
79
|
+
last_failure_at = CASE WHEN ? IN ('degraded', 'unavailable') THEN ? ELSE NULL END,
|
|
80
|
+
last_failure_code = ?, last_failure_retryable = ?,
|
|
81
|
+
consecutive_failures = CASE WHEN ? = 'available' THEN 0 ELSE consecutive_failures + 1 END,
|
|
82
|
+
updated_at = datetime('now')
|
|
83
|
+
WHERE id = ?
|
|
84
|
+
`,args:[e.operationalStatus,t,e.operationalStatus,t,e.operationalStatus,t,e.failureCode??null,e.retryable==null?null:e.retryable?1:0,e.operationalStatus,e.connectionId]}),await o().execute({sql:"INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)",args:[_(),e.connectionId,e.operationalStatus,e.failureCode??null,e.retryable==null?null:e.retryable?1:0,e.evidenceSource]})}async function q(e,t,n){let r=await d(e,t);if(!r||r.lifecycleStatus==="disconnected")throw new Error("service_connection_not_found");return await o().execute({sql:"UPDATE service_connections SET actions_enabled = ?, updated_at = datetime('now') WHERE id = ? AND user_id = ?",args:[n?1:0,t,r.userId]}),n}async function k(e,t){let n=await d(e,t);if(!n)throw new Error("service_connection_not_found");await o().execute({sql:"UPDATE service_connections SET lifecycle_status = 'disconnected', operational_status = 'unknown', reconnect_required = 0, updated_at = datetime('now') WHERE id = ? AND user_id = ?",args:[t,n.userId]});let r=await o().execute({sql:"SELECT COUNT(*) AS count FROM service_connections WHERE user_id = ? AND transport = 'nango' AND lifecycle_status = 'connected'",args:[n.userId]});return Number(r.rows[0]?.count??0)}async function F(e){await c();let t=await d(e.identity,e.connectionId);if(!t)throw new Error("service_connection_not_found");await o().execute({sql:"UPDATE service_connection_action_audit SET status = ?, error_code = ?, result_json = ? WHERE user_id = ? AND request_id = ? AND connection_id = ?",args:[e.status,e.errorCode??null,e.result===void 0?null:JSON.stringify(e.result),t.userId,e.requestId,t.id]})}async function P(e){await c();let t=await d(e.identity,e.connectionId);if(!t)throw new Error("service_connection_not_found");let n=await o().execute({sql:"INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)",args:[_(),t.id,t.userId,e.tool,e.requestId,e.requestDigest]});if(Number(n.rowsAffected??0)===1)return{claimed:!0};let i=(await o().execute({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",args:[t.userId,e.requestId]})).rows[0],s=String(i?.connection_id??"")!==t.id||String(i?.tool??"")!==e.tool||String(i?.request_digest??"")!==e.requestDigest,l;if(!s&&typeof i?.result_json=="string")try{l=JSON.parse(i.result_json)}catch{l=void 0}return{claimed:!1,status:String(i?.status??"unknown"),errorCode:typeof i?.error_code=="string"?i.error_code:null,conflict:s,...l!==void 0?{result:l}:{}}}export{S as a,L as b,I as c,x as d,c as e,D as f,A as g,d as h,w as i,U as j,h as k,X as l,q as m,k as n,F as o,P as p};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import{a as j,b as T,c as P,d as C,f as S}from"./chunk-TMB56NCA.js";import{W as w}from"./chunk-MZN4U5BL.js";import{Bb as N,Kb as D,d as m,e as I,i as u,s}from"./chunk-63T4W2LX.js";import{createHash as W}from"crypto";import{gunzipSync as $,gzipSync as q}from"zlib";var y="site-extracts/",L=10080*60*1e3,H=900*1e3;function U(){return process.env.SITE_EXTRACT_ARTIFACT_READ_WRITE_TOKEN?.trim()||process.env.PRIVATE_ARTIFACT_READ_WRITE_TOKEN?.trim()||process.env.CONNECTED_DATA_READ_WRITE_TOKEN?.trim()||process.env.CONNECTED_DATA_BLOB_READ_WRITE_TOKEN?.trim()||null}function v(){return process.env.VERCEL==="1"||process.env.NODE_ENV==="production"}function p(){return{prefix:y,artifactTtlMs:L,downloadTtlMs:H,token:U()}}function h(t){return j(t,y)}async function V(t){let e=await P({policy:p(),ownerId:t.ownerId,artifactKey:`${t.jobId}.zip`,createdAt:t.createdAt,filename:`${t.jobId}-site-export.zip`,contentType:"application/zip",content:t.content});return{key:e.artifactId,url:e.downloadUrl??"",bytes:e.bytes,contentType:e.contentType,filename:e.filename,sha256:e.sha256,expiresAt:e.expiresAt,downloadUrlExpiresAt:e.downloadUrlExpiresAt,kind:"bundle"}}async function G(t){let e=await T({policy:p(),ownerId:t.ownerId,scopeSegments:[t.jobId,"images"],artifactKey:`${t.imageId}.bin`,createdAt:new Date,filename:t.filename,contentType:t.contentType,content:t.content});return{key:e.artifactId,url:e.downloadUrl??"",bytes:e.bytes,contentType:e.contentType,filename:e.filename,sha256:e.sha256,expiresAt:e.expiresAt,downloadUrlExpiresAt:e.downloadUrlExpiresAt,kind:"image",imageId:t.imageId,sourceUrl:t.sourceUrl,sourcePage:t.sourcePage}}async function O(t){return T({policy:p(),ownerId:t.ownerId,scopeSegments:[t.jobId,"content"],artifactKey:`${t.chunkKey}.json.gz`,createdAt:t.createdAt,filename:`${t.chunkKey}.json.gz`,contentType:"application/gzip",content:t.content})}async function Q(t){return C({policy:p(),artifactId:t.artifactId,ownerId:t.ownerId})}async function J(t){return S({policy:p(),artifactId:t,maxBytes:50*1024*1024})}async function Z(t){return h(t.artifactId)!==t.ownerId?null:J(t.artifactId)}async function k(t){return h(t.artifactId)!==t.ownerId?null:S({policy:p(),artifactId:t.artifactId,maxBytes:25*1024*1024})}async function tt(t){return h(t.artifactId)!==t.ownerId?null:S({policy:p(),artifactId:t.artifactId,maxBytes:10*1024*1024})}async function et(t={}){let e=t.now??new Date,n=U();if(!n)return{deleted:0,store:v()?"none":"local"};if(!t.force&&!(e.getUTCHours()===3&&e.getUTCMinutes()===21))return{deleted:0,store:"private-vercel-blob",skipped:!0};let r=e.getTime()-L,{list:i,del:a}=await import("@vercel/blob"),o,c=0;for(let d=0;d<20;d+=1){let l=await i({prefix:y,token:n,limit:1e3,cursor:o}),f=l.blobs.filter(A=>new Date(A.uploadedAt).getTime()<=r);if(f.length>0&&(await a(f.map(A=>A.pathname),{token:n}),c+=f.length),!l.hasMore||!l.cursor)break;o=l.cursor}return{deleted:c,store:"private-vercel-blob"}}var F=10,b=20*1024*1024;function E(t){return W("sha256").update(t).digest("hex")}function B(t){return!t.acquiredHtml||t.extractionStatus==="failed"?null:{pageId:t.pageId??E(t.archivedUrl??t.url),url:t.archivedUrl??t.url,html:t.acquiredHtml,mainHtml:t.mainHtml??"",markdown:t.bodyMarkdown,htmlSha256:t.htmlSha256??E(t.acquiredHtml),markdownSha256:t.markdownSha256??E(t.bodyMarkdown)}}function R(t){return Buffer.from(JSON.stringify({version:"site-extract-content.v1",pages:t}))}async function M(t){let e=t.pages.flatMap(o=>{let c=B(o);return c?[c]:[]}),n=new Map,r=[],i=0,a=async()=>{if(!r.length)return;let o=R(r);if(o.length>b)throw new Error(`site export content chunk exceeds ${b} bytes`);let c=E(r.map(l=>l.pageId).join("\0")).slice(0,16),d=await O({ownerId:t.ownerId,jobId:t.jobId,createdAt:t.createdAt,chunkKey:`content-${String(i).padStart(4,"0")}-${c}`,content:q(o,{level:6})});for(let l of r)n.set(l.url,{artifactId:d.artifactId,artifactSha256:d.sha256,pageId:l.pageId,uncompressedBytes:o.length});i++,r=[]};for(let o of e){let c=[...r,o];if(r.length>0&&(c.length>F||R(c).length>b)&&await a(),r.push(o),R(r).length>b)throw new Error(`page ${o.pageId} exceeds the durable content chunk limit`)}return await a(),n}function it(t){let e=new Map;return async n=>{let r=e.get(n.artifactId);if(!r){let a=await k({artifactId:n.artifactId,ownerId:t});if(!a)throw new Error("site export content chunk is missing or unauthorized");if(E(a)!==n.artifactSha256)throw new Error("site export content chunk checksum mismatch");let o=$(a);if(o.length>b)throw new Error("site export content chunk exceeds its read limit");if(r=JSON.parse(o.toString("utf8")),r.version!=="site-extract-content.v1"||!Array.isArray(r.pages))throw new Error("site export content chunk has an unsupported contract");for(e.set(n.artifactId,r);e.size>2;)e.delete(e.keys().next().value)}let i=r.pages.find(a=>a.pageId===n.pageId);if(!i)throw new Error("site export page is missing from its content chunk");if(E(i.html)!==i.htmlSha256||E(i.markdown)!==i.markdownSha256)throw new Error("site export page checksum mismatch");return i}}var g="xray_entitlement";function pt(t){let e=Math.max(1,Number(t.options.effectiveMaxPages??t.options.maxPages??1)),n=Math.max(e,Number(t.options.requestedMaxPages??e)),r=n>e;return{requestedMaxPages:n,effectiveMaxPages:e,creditLimited:r,creditTruncated:r&&t.totalUrls>=e}}function Et(t,e=!1){return t.successfulUrls===0?"failed":t.failedUrls>0||t.remainingUrls>0||e?"partial":"complete"}function _(t){let e=Number(t.total_urls??0),n=t.attempted_urls==null,r=Number(n?t.done_urls??0:t.attempted_urls),i=Number(n?t.done_urls??0:t.successful_urls??0),a=Number(t.failed_urls??Math.max(0,r-i));return{id:String(t.id),userId:t.user_id!=null?Number(t.user_id):null,idempotencyKey:t.idempotency_key!=null?String(t.idempotency_key):null,requestFingerprint:t.request_fingerprint!=null?String(t.request_fingerprint):null,status:t.status!=null?String(t.status):"pending",startUrl:String(t.start_url??""),options:t.options?JSON.parse(String(t.options)):{},totalUrls:e,doneUrls:r,attemptedUrls:r,successfulUrls:i,failedUrls:a,remainingUrls:Math.max(0,e-r),artifacts:t.artifacts?JSON.parse(String(t.artifacts)):null,error:t.error!=null?String(t.error):null,publicError:I(t.public_error_json),billedMc:t.billed_mc!=null?Number(t.billed_mc):null,createdAt:String(t.created_at??""),updatedAt:String(t.updated_at??"")}}async function mt(t,e,n,r){await s().execute({sql:`INSERT INTO site_extract_jobs (id, user_id, status, start_url, options, created_at, updated_at)
|
|
2
|
+
VALUES (?, ?, 'pending', ?, ?, datetime('now'), datetime('now'))`,args:[t,e,n,JSON.stringify(r)]})}async function K(t,e){let r=await s().execute({sql:"SELECT * FROM site_extract_jobs WHERE user_id = ? AND idempotency_key = ? LIMIT 1",args:[t,e]});return r.rows[0]?_(r.rows[0]):null}async function gt(t){let n=await s().execute({sql:`INSERT OR IGNORE INTO site_extract_jobs
|
|
3
|
+
(id, user_id, status, start_url, options, idempotency_key, request_fingerprint, created_at, updated_at)
|
|
4
|
+
VALUES (?, ?, 'pending', ?, ?, ?, ?, datetime('now'), datetime('now'))`,args:[t.jobId,t.userId,t.startUrl,JSON.stringify(t.options),t.idempotencyKey,t.requestFingerprint]}),r=await K(t.userId,t.idempotencyKey);if(!r)throw new Error("idempotent extract job was not persisted");return{job:r,created:n.rowsAffected===1,conflict:r.requestFingerprint!==t.requestFingerprint}}async function x(t){let n=await s().execute({sql:"SELECT * FROM site_extract_jobs WHERE id = ?",args:[t]});return n.rows[0]?_(n.rows[0]):null}async function _t(t){return(await s().execute({sql:"SELECT * FROM site_extract_jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50",args:[t]})).rows.map(r=>_(r))}async function xt(t=25){return(await s().execute({sql:`SELECT * FROM site_extract_jobs
|
|
5
|
+
WHERE billed_mc IS NULL AND status IN ('complete', 'partial', 'failed')
|
|
6
|
+
AND (next_settlement_at IS NULL OR next_settlement_at <= datetime('now'))
|
|
7
|
+
ORDER BY updated_at ASC LIMIT ?`,args:[Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(r=>_(r))}async function ft(t=25,e=2){let n=s(),r=Math.max(1,Math.min(60,Math.round(e)));return(await n.execute({sql:`SELECT j.* FROM site_extract_jobs j
|
|
8
|
+
LEFT JOIN billing_debits d
|
|
9
|
+
ON d.idempotency_key = json_extract(j.options, '$.debitKey')
|
|
10
|
+
AND d.user_id = j.user_id
|
|
11
|
+
AND d.status = 'applied'
|
|
12
|
+
WHERE j.status = 'pending'
|
|
13
|
+
AND j.billed_mc IS NULL
|
|
14
|
+
AND (
|
|
15
|
+
d.idempotency_key IS NOT NULL
|
|
16
|
+
OR (
|
|
17
|
+
json_extract(j.options, '$.billingClass') = ?
|
|
18
|
+
AND json_extract(j.options, '$.heldMc') = 0
|
|
19
|
+
AND json_extract(j.options, '$.debitKey') IS NULL
|
|
20
|
+
AND json_extract(j.options, '$.xraySetupReceipt.billingClass') = ?
|
|
21
|
+
AND json_extract(j.options, '$.xraySetupReceipt.consumesMcpScraperCredits') = 0
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
AND (j.next_dispatch_at IS NULL OR j.next_dispatch_at <= datetime('now'))
|
|
25
|
+
AND j.updated_at <= datetime('now', ?)
|
|
26
|
+
ORDER BY j.updated_at ASC LIMIT ?`,args:[g,g,`-${r} minutes`,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(a=>_(a))}async function bt(t){return await s().execute({sql:`UPDATE site_extract_jobs
|
|
27
|
+
SET dispatch_attempts = dispatch_attempts + 1,
|
|
28
|
+
updated_at = datetime('now'),
|
|
29
|
+
next_dispatch_at = datetime('now', '+5 minutes'),
|
|
30
|
+
dispatch_error = NULL,
|
|
31
|
+
status = CASE
|
|
32
|
+
WHEN dispatch_attempts + 1 >= 10 OR created_at <= datetime('now', '-6 hours') THEN 'failed'
|
|
33
|
+
ELSE status
|
|
34
|
+
END,
|
|
35
|
+
error = CASE
|
|
36
|
+
WHEN dispatch_attempts + 1 >= 10 OR created_at <= datetime('now', '-6 hours')
|
|
37
|
+
THEN 'Background crawl was acknowledged repeatedly but never started; the hold will be refunded.'
|
|
38
|
+
ELSE error
|
|
39
|
+
END
|
|
40
|
+
WHERE id = ? AND status = 'pending'`,args:[t]}),x(t)}async function wt(t,e){let n=s(),r=u(e).slice(0,1e3);return await n.execute({sql:`UPDATE site_extract_jobs SET
|
|
41
|
+
dispatch_attempts = dispatch_attempts + 1,
|
|
42
|
+
dispatch_error = ?,
|
|
43
|
+
next_dispatch_at = datetime('now', '+5 minutes'),
|
|
44
|
+
updated_at = datetime('now'),
|
|
45
|
+
status = CASE
|
|
46
|
+
WHEN dispatch_attempts + 1 >= 10 OR created_at <= datetime('now', '-6 hours') THEN 'failed'
|
|
47
|
+
ELSE status
|
|
48
|
+
END,
|
|
49
|
+
error = CASE
|
|
50
|
+
WHEN dispatch_attempts + 1 >= 10 OR created_at <= datetime('now', '-6 hours')
|
|
51
|
+
THEN 'Background crawl could not be dispatched after repeated attempts; the hold will be refunded.'
|
|
52
|
+
ELSE error
|
|
53
|
+
END
|
|
54
|
+
WHERE id = ? AND status = 'pending'`,args:[r,t]}),x(t)}async function St(t,e){await s().execute({sql:`UPDATE site_extract_jobs SET
|
|
55
|
+
settlement_attempts = settlement_attempts + 1,
|
|
56
|
+
settlement_error = ?,
|
|
57
|
+
next_settlement_at = datetime('now', '+15 minutes'),
|
|
58
|
+
updated_at = datetime('now')
|
|
59
|
+
WHERE id = ? AND billed_mc IS NULL`,args:[u(e).slice(0,1e3),t]})}async function At(t=25,e=60){let n=s(),r=Math.max(15,Math.min(1440,Math.round(e)));return(await n.execute({sql:`SELECT j.* FROM site_extract_jobs j
|
|
60
|
+
LEFT JOIN billing_debits d
|
|
61
|
+
ON d.idempotency_key = json_extract(j.options, '$.debitKey')
|
|
62
|
+
AND d.user_id = j.user_id
|
|
63
|
+
AND d.status = 'applied'
|
|
64
|
+
WHERE j.status = 'running'
|
|
65
|
+
AND j.billed_mc IS NULL
|
|
66
|
+
AND (
|
|
67
|
+
json_extract(j.options, '$.debitKey') IS NULL
|
|
68
|
+
OR d.idempotency_key IS NOT NULL
|
|
69
|
+
)
|
|
70
|
+
AND j.updated_at <= datetime('now', ?)
|
|
71
|
+
ORDER BY j.updated_at ASC LIMIT ?`,args:[`-${r} minutes`,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(a=>_(a))}async function Nt(t,e=60){let n=s(),r=Math.max(15,Math.min(1440,Math.round(e)));return(await n.execute({sql:`UPDATE site_extract_jobs
|
|
72
|
+
SET status = 'failed',
|
|
73
|
+
error = 'Background crawl stopped without a heartbeat; completed pages were preserved and settlement is pending.',
|
|
74
|
+
public_error_json = ?,
|
|
75
|
+
updated_at = datetime('now')
|
|
76
|
+
WHERE id = ?
|
|
77
|
+
AND status = 'running'
|
|
78
|
+
AND billed_mc IS NULL
|
|
79
|
+
AND updated_at <= datetime('now', ?)`,args:[m({error_code:"extraction_failed",error_type:"extraction",message:"The background crawl stopped without a heartbeat. Completed pages were preserved; retry after settlement completes.",retryable:!0,charge_status:"refund_pending"}),t,`-${r} minutes`]})).rowsAffected===1}async function Tt(t){return(await s().execute({sql:`UPDATE site_extract_jobs
|
|
80
|
+
SET status = 'running', updated_at = datetime('now')
|
|
81
|
+
WHERE id = ? AND status = 'failed'`,args:[t]})).rowsAffected!==1?null:x(t)}async function yt(t,e){await s().execute({sql:`UPDATE site_extract_jobs SET billed_mc = 0, settlement_error = ?, updated_at = datetime('now')
|
|
82
|
+
WHERE id = ? AND billed_mc IS NULL`,args:[u(e).slice(0,1e3),t]})}async function ht(t,e){await s().execute({sql:`UPDATE site_extract_jobs
|
|
83
|
+
SET status = 'running', total_urls = MAX(total_urls, ?), updated_at = datetime('now')
|
|
84
|
+
WHERE id = ? AND status IN ('pending', 'running')`,args:[e,t]})}async function Rt(t,e){if(e.length===0)return;let n=s(),r=await x(t),i=r?.userId!=null?await M({ownerId:String(r.userId),jobId:t,createdAt:r.createdAt,pages:e}):new Map;await n.batch([...e.map(a=>{let{discoveryLinks:o,acquiredHtml:c,mainHtml:d,...l}=a;return l.contentRef=i.get(a.archivedUrl??a.url)??a.contentRef,{sql:`INSERT INTO site_extract_pages (job_id, url, page)
|
|
85
|
+
SELECT ?, ?, ?
|
|
86
|
+
WHERE EXISTS (
|
|
87
|
+
SELECT 1 FROM site_extract_jobs
|
|
88
|
+
WHERE id = ? AND status IN ('pending', 'running')
|
|
89
|
+
)
|
|
90
|
+
ON CONFLICT(job_id, url) DO UPDATE SET page = excluded.page
|
|
91
|
+
WHERE NOT CASE
|
|
92
|
+
WHEN json_valid(site_extract_pages.page) = 0 THEN 0
|
|
93
|
+
WHEN json_extract(site_extract_pages.page, '$.extractionStatus') IS NOT NULL
|
|
94
|
+
THEN json_extract(site_extract_pages.page, '$.extractionStatus') = 'successful'
|
|
95
|
+
ELSE COALESCE(
|
|
96
|
+
json_extract(site_extract_pages.page, '$.status') >= 200
|
|
97
|
+
AND json_extract(site_extract_pages.page, '$.status') < 300
|
|
98
|
+
AND json_extract(site_extract_pages.page, '$.wordCount') > 0,
|
|
99
|
+
0
|
|
100
|
+
)
|
|
101
|
+
END
|
|
102
|
+
OR CASE
|
|
103
|
+
WHEN json_valid(excluded.page) = 0 THEN 0
|
|
104
|
+
WHEN json_extract(excluded.page, '$.extractionStatus') IS NOT NULL
|
|
105
|
+
THEN json_extract(excluded.page, '$.extractionStatus') = 'successful'
|
|
106
|
+
ELSE COALESCE(
|
|
107
|
+
json_extract(excluded.page, '$.status') >= 200
|
|
108
|
+
AND json_extract(excluded.page, '$.status') < 300
|
|
109
|
+
AND json_extract(excluded.page, '$.wordCount') > 0,
|
|
110
|
+
0
|
|
111
|
+
)
|
|
112
|
+
END`,args:[t,a.archivedUrl??a.url,JSON.stringify(l),t]}}),{sql:`UPDATE site_extract_jobs SET
|
|
113
|
+
done_urls = (SELECT COUNT(*) FROM site_extract_pages WHERE job_id = ?),
|
|
114
|
+
attempted_urls = (SELECT COUNT(*) FROM site_extract_pages WHERE job_id = ?),
|
|
115
|
+
successful_urls = (
|
|
116
|
+
SELECT COUNT(*) FROM site_extract_pages
|
|
117
|
+
WHERE job_id = ? AND CASE
|
|
118
|
+
WHEN json_extract(page, '$.extractionStatus') IS NOT NULL
|
|
119
|
+
THEN json_extract(page, '$.extractionStatus') = 'successful'
|
|
120
|
+
ELSE json_extract(page, '$.status') >= 200
|
|
121
|
+
AND json_extract(page, '$.status') < 300
|
|
122
|
+
AND json_extract(page, '$.wordCount') > 0
|
|
123
|
+
END
|
|
124
|
+
),
|
|
125
|
+
failed_urls = (
|
|
126
|
+
SELECT COUNT(*) FROM site_extract_pages
|
|
127
|
+
WHERE job_id = ? AND NOT CASE
|
|
128
|
+
WHEN json_extract(page, '$.extractionStatus') IS NOT NULL
|
|
129
|
+
THEN json_extract(page, '$.extractionStatus') = 'successful'
|
|
130
|
+
ELSE COALESCE(
|
|
131
|
+
json_extract(page, '$.status') >= 200
|
|
132
|
+
AND json_extract(page, '$.status') < 300
|
|
133
|
+
AND json_extract(page, '$.wordCount') > 0,
|
|
134
|
+
0
|
|
135
|
+
)
|
|
136
|
+
END
|
|
137
|
+
),
|
|
138
|
+
updated_at = datetime('now')
|
|
139
|
+
WHERE id = ? AND status IN ('pending', 'running')`,args:[t,t,t,t,t]}],"write")}async function It(t){return(await s().execute({sql:"SELECT page FROM site_extract_pages WHERE job_id = ? ORDER BY rowid",args:[t]})).rows.map(r=>JSON.parse(String(r.page)))}async function Dt(t){return(await s().execute({sql:"SELECT page FROM site_extract_pages WHERE job_id = ?",args:[t]})).rows.map(r=>JSON.parse(String(r.page)))}async function jt(t,e=181){let n=s(),r=Math.max(1,Math.min(5001,Math.round(e)));return(await n.execute({sql:`SELECT DISTINCT CAST(images.value AS TEXT) AS url
|
|
140
|
+
FROM site_extract_pages p,
|
|
141
|
+
json_each(CASE WHEN json_valid(p.page) THEN p.page ELSE '{}' END, '$.imageLinks') images
|
|
142
|
+
WHERE p.job_id = ?
|
|
143
|
+
AND images.type = 'text'
|
|
144
|
+
AND length(CAST(images.value AS TEXT)) BETWEEN 1 AND 4096
|
|
145
|
+
LIMIT ?`,args:[t,r]})).rows.map(a=>String(a.url))}async function Pt(t){let n=await s().execute({sql:`SELECT COUNT(*) AS n FROM site_extract_pages
|
|
146
|
+
WHERE job_id = ? AND CASE
|
|
147
|
+
WHEN json_extract(page, '$.extractionStatus') IS NOT NULL
|
|
148
|
+
THEN json_extract(page, '$.extractionStatus') = 'successful'
|
|
149
|
+
ELSE COALESCE(
|
|
150
|
+
json_extract(page, '$.status') >= 200
|
|
151
|
+
AND json_extract(page, '$.status') < 300
|
|
152
|
+
AND json_extract(page, '$.wordCount') > 0,
|
|
153
|
+
0
|
|
154
|
+
)
|
|
155
|
+
END`,args:[t]});return Number(n.rows[0]?.n??0)}async function Ct(t){let n=await s().execute({sql:"SELECT url FROM site_extract_pages WHERE job_id = ?",args:[t]});return new Set(n.rows.map(r=>String(r.url)))}async function z(t,e,n,r=null,i=!1,a=null){return(await s().execute({sql:`UPDATE site_extract_jobs
|
|
156
|
+
SET status = ?, artifacts = ?, error = ?, public_error_json = ?, updated_at = datetime('now')
|
|
157
|
+
WHERE id = ? AND (status IN ('pending', 'running') OR (? = 1 AND status = 'failed'))`,args:[n,JSON.stringify(e??[]),r?u(r).slice(0,2e3):null,m(a),t,i?1:0]})).rowsAffected===1}async function Lt(t,e){await z(t,e,"complete")}async function Ut(t,e,n){await s().execute({sql:`UPDATE site_extract_jobs
|
|
158
|
+
SET status = 'failed', error = ?, public_error_json = ?, updated_at = datetime('now')
|
|
159
|
+
WHERE id = ? AND status IN ('pending', 'running')`,args:[u(e).slice(0,2e3),m(n),t]})}async function Ot(t,e,n){await s().execute({sql:`UPDATE site_extract_jobs
|
|
160
|
+
SET status = 'failed', billed_mc = 0, error = ?, public_error_json = ?, updated_at = datetime('now')
|
|
161
|
+
WHERE id = ? AND status = 'pending' AND billed_mc IS NULL`,args:[u(e).slice(0,2e3),m(n),t]})}async function kt(t,e){let r=(await x(t))?.options.billingClass===g&&e?{...e,charge_status:"not_charged"}:e;await s().execute({sql:`UPDATE site_extract_jobs SET public_error_json = ?, updated_at = datetime('now')
|
|
162
|
+
WHERE id = ? AND status IN ('complete', 'partial', 'failed')`,args:[m(r),t]})}async function Mt(t,e,n,r,i){let a=s(),o=await x(t);if(!o||o.billedMc!=null)return;if(o.options.billingClass===g){if(!await X(t))throw new Error("xray_extract_zero_charge_finalization_rejected");return}let c=typeof o.options.debitKey=="string"?o.options.debitKey:null;if(c){let f=await D(e,c,Math.max(0,r),w.EXTRACT_SITE_REFUND,i,"extract_site");await a.execute({sql:"UPDATE site_extract_jobs SET billed_mc = ?, updated_at = datetime('now') WHERE id = ? AND billed_mc IS NULL",args:[f.final_amount_mc,t]});return}let d=Math.max(0,n),l=Math.max(0,r);await a.batch([{sql:"UPDATE site_extract_jobs SET billed_mc = -1 WHERE id = ? AND billed_mc IS NULL",args:[t]},{sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, expires_at)
|
|
163
|
+
SELECT ?, ?, ?, ?, datetime(j.created_at, ?)
|
|
164
|
+
FROM site_extract_jobs j
|
|
165
|
+
WHERE j.id = ?
|
|
166
|
+
AND j.billed_mc = -1
|
|
167
|
+
AND ? > 0
|
|
168
|
+
AND changes() = 1
|
|
169
|
+
AND datetime(j.created_at, ?) > datetime('now')`,args:[e,d,d,w.EXTRACT_SITE_REFUND,N,t,d,N]},{sql:`UPDATE users SET balance_mc = balance_mc + ?
|
|
170
|
+
WHERE id = ? AND ? > 0 AND changes() = 1`,args:[d,e,d]},{sql:`INSERT INTO ledger (user_id, amount_mc, operation, description)
|
|
171
|
+
SELECT ?, ?, ?, ? WHERE ? > 0 AND changes() = 1`,args:[e,d,w.EXTRACT_SITE_REFUND,i,d]},{sql:`UPDATE site_extract_jobs SET billed_mc = ?, updated_at = datetime('now')
|
|
172
|
+
WHERE id = ? AND billed_mc = -1`,args:[l,t]}],"write")}async function X(t){return(await s().execute({sql:`UPDATE site_extract_jobs
|
|
173
|
+
SET billed_mc = 0, updated_at = datetime('now')
|
|
174
|
+
WHERE id = ?
|
|
175
|
+
AND billed_mc IS NULL
|
|
176
|
+
AND json_extract(options, '$.billingClass') = ?
|
|
177
|
+
AND json_extract(options, '$.heldMc') = 0
|
|
178
|
+
AND json_extract(options, '$.debitKey') IS NULL
|
|
179
|
+
AND json_extract(options, '$.xraySetupReceipt.billingClass') = ?
|
|
180
|
+
AND json_extract(options, '$.xraySetupReceipt.consumesMcpScraperCredits') = 0
|
|
181
|
+
AND json_extract(options, '$.xraySetupReceipt.heldMc') = 0
|
|
182
|
+
AND json_extract(options, '$.xraySetupReceipt.billedMc') = 0`,args:[t,g,g]})).rowsAffected===1}export{y as a,V as b,G as c,Q as d,Z as e,tt as f,et as g,it as h,g as i,pt as j,Et as k,mt as l,K as m,gt as n,x as o,_t as p,xt as q,ft as r,bt as s,wt as t,St as u,At as v,Nt as w,Tt as x,yt as y,ht as z,Rt as A,It as B,Dt as C,jt as D,Pt as E,Ct as F,z as G,Lt as H,Ut as I,Ot as J,kt as K,Mt as L,X as M};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import{a as Ge,f as de,h as le,i as De,j as Ue,l as ue}from"./chunk-D6IQJP64.js";import{c as Pe,d as Me}from"./chunk-HUV2WTRW.js";import{W as G,e as V,q as C,t as ce,u as Re,v as ke,w as W,y as Oe}from"./chunk-MZN4U5BL.js";import{b as ae,h as se}from"./chunk-RYNHNEF3.js";import{Jb as re,M as Ne,Ob as X,s as y}from"./chunk-63T4W2LX.js";import{createHash as Te,createHmac as pt,timingSafeEqual as on}from"crypto";import{createHash as D,randomUUID as He}from"crypto";import{Client as Mt,StreamableHTTPClientTransport as Gt}from"@modelcontextprotocol/client";import{createHash as vt,randomUUID as St}from"crypto";import{z as b}from"zod";async function _n(e,t){!Number.isFinite(t)||t<=0||await ae({op:G.CONNECTED_ACCOUNT_FEE,userId:Number(e)},()=>se({vendor:"nango_connection",units:t,unitType:"connection_month"}))}async function qe(e,t){let n=[{vendor:"nango_function_run",units:t.functionRuns,unitType:"function_run"},{vendor:"nango_proxy_request",units:t.proxyRequests,unitType:"proxy_request"},{vendor:"nango_compute",units:t.computeMilliseconds/1e3,unitType:"compute_second"}];await ae({op:G.CONNECTED_USAGE,userId:Number(e)},async()=>{for(let i of n)!Number.isFinite(i.units)||i.units<=0||await se(i)})}var R="connected_usage",Ct="mastra_scheduler",xt=b.object({toolName:b.string().trim().min(1).max(200).optional(),operationKind:b.enum(["read","action","sync","export","proxy","other"]).optional(),outcome:b.enum(["success","error","partial"]).optional(),requestId:b.string().trim().min(1).max(200).optional(),occurrenceId:b.string().trim().min(1).max(200).optional(),scheduleId:b.string().trim().min(1).max(200).optional(),nangoOperationId:b.string().trim().min(1).max(200).optional(),startedAt:b.string().datetime({offset:!0}).optional(),completedAt:b.string().datetime({offset:!0}).optional()}).strict(),Tt=b.object({identity:b.string().trim().min(1).max(320),idempotencyKey:b.string().trim().min(1).max(500),ratePolicyVersion:b.string().trim().min(1).max(100),connectionId:b.string().trim().min(1).max(500),providerConfigKey:b.string().trim().min(1).max(200),functionRuns:b.number().int().safe().nonnegative(),proxyRequests:b.number().int().safe().nonnegative(),computeMilliseconds:b.number().int().safe().nonnegative(),sourceSurface:b.enum(["main_mcp","mastra_scheduler","nango_reconciliation"]).default(Ct),metadata:xt.optional()}).strict(),Et=b.object({identity:b.string().trim().min(1).max(320),ratePolicyVersion:b.string().trim().min(1).max(100)}).strict(),x=class extends Error{constructor(n,i,r,o={}){super(i);this.code=n;this.httpStatus=r;this.details=o;this.name="ConnectedUsageBillingError"}code;httpStatus;details};function ge(e){return vt("sha256").update(e).digest("hex")}function At(e){return`connected-usage:${ge(e)}`}function Nt(e){return`connected-usage-debit:${ge(e)}`}function Rt(e){return e.trim().toLowerCase()}async function Le(e){let t=await Ne(Rt(e));if(!t)throw new x("user_not_found","billing identity was not found",404);return t}function kt(e){let t={toolName:e.metadata.toolName??null,operationKind:e.metadata.operationKind??null,outcome:e.metadata.outcome??null,requestId:e.metadata.requestId??null,occurrenceId:e.metadata.occurrenceId??null,scheduleId:e.metadata.scheduleId??null,nangoOperationId:e.metadata.nangoOperationId??null,startedAt:e.metadata.startedAt??null,completedAt:e.metadata.completedAt??null};return ge(JSON.stringify({ratePolicyVersion:C,connectionId:e.connectionId,providerConfigKey:e.providerConfigKey,usage:e.usage,sourceSurface:e.sourceSurface,metadata:t}))}function K(e){let t=JSON.stringify(e);if(t.length>4e3)throw new x("invalid_request","connected usage metadata is too large",400);return t}function ye(e){try{let t=JSON.parse(e.metadata??"");if(t.contract!=="connected_usage_receipt"||t.ratePolicyVersion!==C||typeof t.fingerprint!="string"||typeof t.connectionId!="string"||typeof t.providerConfigKey!="string"||!t.usage||!t.charge)throw new Error("invalid connected usage receipt metadata");return t}catch{throw new x("idempotency_key_conflict","the idempotency key is already bound to an incompatible billing receipt",409)}}async function me(e){let t=await y().execute({sql:"SELECT id, user_id, billing_class, source_surface, status, amount_mc, metadata FROM billing_events WHERE idempotency_key = ? LIMIT 1",args:[e]});return t.rows[0]?t.rows[0]:null}async function Ke(e,t){return(await y().execute({sql:`SELECT 1
|
|
2
|
+
FROM billing_events
|
|
3
|
+
WHERE user_id = ?
|
|
4
|
+
AND billing_class = ?
|
|
5
|
+
AND status = 'cost_pending'
|
|
6
|
+
${t?"AND idempotency_key <> ?":""}
|
|
7
|
+
LIMIT 1`,args:t?[e,R,t]:[e,R]})).rows.length>0}function Ot(e){let t="connected-usage:",n=e.startsWith(t)?e.slice(t.length):"";return/^[a-f0-9]{64}$/.test(n)?`connected-usage-debit:${n}`:null}async function Pt(e){let t=await y().execute({sql:`SELECT id, user_id, idempotency_key, billing_class, source_surface, status, amount_mc, metadata
|
|
8
|
+
FROM billing_events
|
|
9
|
+
WHERE user_id = ? AND billing_class = ? AND status = 'cost_pending'
|
|
10
|
+
ORDER BY created_at ASC
|
|
11
|
+
LIMIT 10`,args:[e.id,R]});for(let n of t.rows){let i=n,r=String(i.idempotency_key??""),o=Ot(r),a;try{a=ye(i)}catch{return}if(!o||Number(i.user_id)!==e.id||i.billing_class!==R||Number(i.amount_mc)!==a.charge.amountMc||a.charge.amountMc>0&&!(await re(e.id,a.charge.amountMc,G.CONNECTED_USAGE,`connected-usage:${a.providerConfigKey}`,o)).ok)return;let s={...a};delete s.reason,await y().execute({sql:`UPDATE billing_events
|
|
12
|
+
SET status = 'settled', metadata = ?, settled_at = datetime('now')
|
|
13
|
+
WHERE idempotency_key = ? AND user_id = ? AND billing_class = ? AND status = 'cost_pending'`,args:[K(s),r,e.id,R]})}}function $e(e){if(e!==C)throw new x("rate_policy_mismatch","connected usage receipt rate policy does not match the active policy",409,{expectedRatePolicyVersion:C})}async function he(e){let t=Et.safeParse(e);if(!t.success)throw new x("invalid_request","invalid connected usage preflight request",400);$e(t.data.ratePolicyVersion);let n=await Le(t.data.identity);if(await Pt(n),await Ke(n.id))throw new x("pending_cost","a previous connected usage receipt has unresolved cost",409);let i=await X(n.id,n.balance_mc);if(i<W)throw new x("insufficient_credits","the wallet cannot cover the minimum connected function charge",402,{balanceMc:i,requiredMc:W});return{allowed:!0,ratePolicyVersion:C,minimumMc:W,minimumCredits:ce,balanceMc:i}}function pe(e,t,n,i,r){let o=ye(e);if(Number(e.user_id)!==t||e.billing_class!==R||e.source_surface!==n||Number(e.amount_mc)!==r||o.fingerprint!==i)throw new x("idempotency_key_conflict","the idempotency key is already bound to different connected usage",409);return o}function je(e,t){return[{key:"function_runs",label:"Connected function runs",quantity:e.functionRuns,quantityUnit:"function_run",rateCredits:ce,rateUnit:"function_run",amountMc:t.functionRunMc,credits:t.functionRunMc/V},{key:"proxy_requests",label:"Connected proxy requests",quantity:e.proxyRequests,quantityUnit:"proxy_request",rateCredits:Re,rateUnit:"proxy_request",amountMc:t.proxyRequestMc,credits:t.proxyRequestMc/V},{key:"compute",label:"Connected function compute",quantity:e.computeMilliseconds,quantityUnit:"millisecond",rateCredits:ke,rateUnit:"compute_second",amountMc:t.computeMc,credits:t.computeMc/V}]}function fe(e,t,n,i){let r=e.status==="cost_pending"?t.reason:void 0;return{id:e.id,status:e.status==="settled"?"settled":"cost_pending",ratePolicyVersion:C,connectionId:t.connectionId,providerConfigKey:t.providerConfigKey,amountMc:t.charge.amountMc,credits:t.charge.credits,functionRunMc:t.charge.functionRunMc,proxyRequestMc:t.charge.proxyRequestMc,computeMc:t.charge.computeMc,usage:t.usage,costBreakdown:je(t.usage,t.charge),balanceMc:n,...r?{reason:r}:{},duplicate:i}}async function we(e){let t=Tt.safeParse(e);if(!t.success)throw new x("invalid_request","invalid connected usage settlement request",400,{fields:[...new Set(t.error.issues.map(I=>I.path.join(".")).filter(Boolean))]});let n=t.data;$e(n.ratePolicyVersion);let i=await Le(n.identity),r={functionRuns:n.functionRuns,proxyRequests:n.proxyRequests,computeMilliseconds:n.computeMilliseconds},o=Oe(r),a=n.metadata??{},s=kt({connectionId:n.connectionId,providerConfigKey:n.providerConfigKey,usage:r,sourceSurface:n.sourceSurface,metadata:a}),c={contract:"connected_usage_receipt",ratePolicyVersion:C,fingerprint:s,connectionId:n.connectionId,providerConfigKey:n.providerConfigKey,usage:r,charge:o,safeMetadata:a},d=At(n.idempotencyKey);if(await Ke(i.id,d))throw new x("pending_cost","a previous connected usage receipt has unresolved cost",409);let l=await y().execute({sql:`INSERT OR IGNORE INTO billing_events
|
|
14
|
+
(id, user_id, idempotency_key, billing_class, source_surface, status, amount_mc, metadata)
|
|
15
|
+
VALUES (?, ?, ?, ?, ?, 'settling', ?, ?)`,args:[St(),i.id,d,R,n.sourceSurface,o.amountMc,K(c)]}),u=await me(d);if(!u)throw new Error("connected usage receipt insert completed without a readable event");let p=pe(u,i.id,n.sourceSurface,s,o.amountMc),_=l.rowsAffected===0;if(u.status==="settled")return fe(u,p,await X(i.id,i.balance_mc),!0);if(!["settling","cost_pending"].includes(u.status))throw new x("idempotency_key_conflict","the connected usage receipt has an incompatible status",409);if(u.status==="cost_pending"&&await y().execute({sql:"UPDATE billing_events SET status = 'settling', metadata = ? WHERE idempotency_key = ? AND status = 'cost_pending'",args:[K(c),d]}),o.amountMc===0)await y().execute({sql:"UPDATE billing_events SET status = 'settled', settled_at = datetime('now') WHERE idempotency_key = ? AND status = 'settling'",args:[d]});else{let I=await re(i.id,o.amountMc,G.CONNECTED_USAGE,`connected-usage:${n.providerConfigKey}`,Nt(n.idempotencyKey));if(!I.ok){let M={...c,reason:"insufficient_credits"};if(await y().execute({sql:"UPDATE billing_events SET status = 'cost_pending', metadata = ? WHERE idempotency_key = ? AND status = 'settling'",args:[K(M),d]}),u=await me(d),!u)throw new Error("connected usage pending receipt was lost");return p=pe(u,i.id,n.sourceSurface,s,o.amountMc),fe(u,p,I.balance_mc,_||I.duplicate)}await y().execute({sql:"UPDATE billing_events SET status = 'settled', metadata = ?, settled_at = datetime('now') WHERE idempotency_key = ? AND status IN ('settling', 'cost_pending')",args:[K(c),d]}),I.duplicate||await qe(i.id,r)}if(u=await me(d),!u)throw new Error("connected usage settlement completed without an event receipt");return p=pe(u,i.id,n.sourceSurface,s,o.amountMc),fe(u,p,await X(i.id,i.balance_mc),_)}async function Tn(e,t=100){let n=await y().execute({sql:`SELECT id, user_id, billing_class, source_surface, status, amount_mc, metadata, created_at
|
|
16
|
+
FROM billing_events
|
|
17
|
+
WHERE user_id = ? AND billing_class = ? AND status IN ('settled', 'cost_pending')
|
|
18
|
+
ORDER BY created_at DESC
|
|
19
|
+
LIMIT ?`,args:[e,R,Math.max(1,Math.min(250,Math.round(t)))]}),i=[];for(let r of n.rows){let o=r;try{let a=ye(o);i.push({id:o.id,createdAt:String(o.created_at??""),status:o.status==="settled"?"settled":"cost_pending",connectionId:a.connectionId,providerConfigKey:a.providerConfigKey,amountMc:a.charge.amountMc,credits:a.charge.credits,usage:a.usage,costBreakdown:je(a.usage,a.charge),metadata:a.safeMetadata})}catch{}}return i}function _e(e){return e.annotations?.readOnlyHint===!0?"read":e.annotations?.readOnlyHint===!1?"action":/^(get|list|search|query|read|download|fetch|find|lookup|inspect|describe|check)-/i.test(e.name)?"read":"action"}function Be(e){return new Map(Object.entries(e??{}).map(([t,n])=>[t,[...new Set(n.map(i=>i.trim()).filter(Boolean))].sort()]))}function Y(e){let t=Be(e.requiredPermissionsByTool),n=Be(e.requiredFeaturesByTool),i=new Set(e.grantedPermissions??[]),r=new Set(e.enabledFeatures??[]),o=new Set(e.adminBlockedTools??[]),a=new Map;for(let s of e.tools){let c=_e(s),d=t.get(s.name)??[],l=n.get(s.name)??[],u=d.filter(I=>!i.has(I)),p=l.filter(I=>!r.has(I)),_=e.connectionActive?o.has(s.name)?"admin_blocked":c==="action"&&!e.actionsEnabled?"actions_disabled":d.length>0&&e.permissionVerification==="unavailable"?"permission_verification_unavailable":u.length>0?"missing_permission":p.length>0?"missing_app_feature":null:"inactive_connection";a.set(s.name,{name:s.name,classification:c,requiredPermissions:d,requiredFeatures:l,available:_===null,blockedReason:_,missingPermissions:u,missingFeatures:p})}return a}function Ie(e,t){let n=e.get(t);if(!n)throw new Error("connected_tool_policy_missing");return n}var Dt="https://api.nango.dev/mcp",Ut=2e4,qt=24e4,Fe=100,Lt=20,Kt=360*60*1e3,$t=new Set(["stripe_revenue","salesforce","pipedrive"]),jt="2026-07-16.1",Bt="f037859ec80c2ea2fac6e4a67c1a59f3200dd22d3642c97789b9bb3236723d3e",w=class extends Error{status;code;retryable;retryAfterMs;constructor(t,n,i,r=n===429||n>=500,o=null){super(t),this.name="MainNangoTransportError",this.status=n,this.code=i,this.retryable=r,this.retryAfterMs=o}};function Q(e){return typeof e=="string"&&$t.has(e.normalize("NFKC").trim().toLowerCase())}function ze(e){if(Q(e))throw new w("This provider integration is not currently available.",409,"provider_unavailable",!1)}function Ft(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return""}}function Je(e){let t=e.match(/retry[_ -]?after[_ -]?ms[^0-9]{0,20}(\d{1,7})/i);if(t)return Math.min(Math.max(Number(t[1]),1e3),6e4);let n=e.match(/retry[_ -]?after[^0-9]{0,20}(\d{1,4})/i);return n?Math.min(Math.max(Number(n[1]),1)*1e3,6e4):null}function Xe(e){if(e instanceof w)return e;let t=Ft(e),n=e&&typeof e=="object"?e:null;return n?.code===-32001||n?.name==="RequestTimeout"||/Request timed out|RequestTimeout|Maximum total timeout exceeded/i.test(t)?new w("The connected service operation timed out before returning a result. Retry failed items or use a smaller batch.",503,"mcp_request_timeout",!0):/SERVICE_DISABLED|accessNotConfigured/i.test(t)?new w("The provider API required by this connection is disabled. Enable it in the provider project, wait for propagation, then retry.",409,"provider_api_disabled",!1):/PERMISSION_DENIED|insufficientPermissions|insufficient permission/i.test(t)?new w("The connected account does not have permission to run this provider operation.",403,"missing_provider_permission",!1):/RESOURCE_EXHAUSTED|rate.?limit|status["']?\s*:\s*429/i.test(t)?new w("The connected provider is temporarily rate limited.",429,"upstream_rate_limited",!0,Je(t)):/UNAUTHENTICATED|invalid_grant|status["']?\s*:\s*401/i.test(t)?new w("The service connection requires reconnection.",409,"connection_inactive",!1):new w("The service connection is temporarily unavailable.",503,"connection_transport_unavailable")}async function Ht(e,t,n){return e.callTool({name:t,arguments:n},{timeout:qt})}function g(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function m(e){return typeof e=="string"&&e.trim()?e.trim():null}function be(e,t){if(Array.isArray(e))return e;let n=g(e);if(Array.isArray(n?.[t]))return n[t];if(Array.isArray(n?.data))return n.data;let i=g(n?.data);return Array.isArray(i?.[t])?i[t]:[]}function Ve(){let e=process.env.NANGO_SECRET_KEY?.trim();if(!e)throw new w("Nango is not configured.",503,"nango_not_configured");return e}function We(){try{return new URL(process.env.NANGO_MCP_URL?.trim()||Dt)}catch{throw new w("Nango MCP URL is invalid.",503,"nango_invalid_url")}}async function P(e,t={}){let n=new URL(e,`${We().origin}/`);for(let[a,s]of Object.entries(t.query??{}))s!==void 0&&n.searchParams.set(a,String(s));let i;try{i=await fetch(n,{method:t.method??"GET",headers:{authorization:`Bearer ${Ve()}`,accept:"application/json",...t.body?{"content-type":"application/json"}:{},...t.headers},body:t.body?JSON.stringify(t.body):void 0,signal:AbortSignal.timeout(Ut)})}catch{throw new w("Nango is temporarily unavailable.",503,"connection_transport_unavailable")}let r=await i.text(),o={};try{o=r?JSON.parse(r):{}}catch{throw new w("Nango returned an invalid response.",502,"nango_invalid_response")}if(!i.ok){let a=i.status===400||i.status===403||i.status===404||i.status===409||i.status===429||i.status===503?i.status:502;throw new w(a===429?"The connected provider is temporarily rate limited.":"Nango request failed.",a,a===429?"upstream_rate_limited":a===404?"connection_not_found":"connection_transport_unavailable",a===429||a>=500,a===429?Je(`retry-after: ${i.headers.get("retry-after")??""}`):null)}return o}function $(e){let t=m(e);return t?t.normalize("NFKC").toLowerCase():null}function zt(e,t){let n=g(e),i=g(n?.tags),r=g(n?.end_user),o=$(t);if(!o)return!1;let a=[$(i?.end_user_email),$(r?.email)].filter(c=>!!c);if(a.some(c=>c!==o))return!1;let s=[$(i?.end_user_id),$(r?.id)].filter(c=>!!c&&c.includes("@"));return s.some(c=>c!==o)?!1:a.length>0?a.includes(o):s.includes(o)}function Jt(e){let t=g(e),n=m(t?.connection_id),i=m(t?.provider_config_key);if(!n||!i)return null;let o=(Array.isArray(t?.errors)?t.errors:[]).some(a=>m(g(a)?.type)==="auth");return{upstreamConnectionId:n,providerConfigKey:i,provider:m(t?.provider)??i,label:null,lifecycleStatus:o?"needs_reauth":"connected",reconnectRequired:o,createdAt:m(t?.created_at)??m(t?.created),updatedAt:m(t?.updated_at)}}var Xt=new Set(["facebook","github-getting-started","google-analytics","google-calendar","google-drive","google-mail","google-search-console","linkedin","meta-marketing-api","slack","twitter-v2","xero","youtube","zoom"]);function Vt(e){let t=m(e);return t||(typeof e=="number"&&Number.isFinite(e)?String(e):null)}function O(e){let t=m(e)?.toLowerCase()??null;return t&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)?t:null}function T(e){return e.id||e.email||e.name?e:null}async function k(e){return P(`/proxy${e.path}`,{query:e.query,headers:{"connection-id":e.upstreamConnectionId,"provider-config-key":e.providerConfigKey,...e.baseUrlOverride?{"base-url-override":e.baseUrlOverride}:{}}})}var Wt=[{method:"GET",pattern:/^\/gmail\/v1\/users\/me\/messages$/},{method:"GET",pattern:/^\/gmail\/v1\/users\/me\/messages\/[A-Za-z0-9_-]+$/},{method:"GET",pattern:/^\/gmail\/v1\/users\/me\/messages\/[A-Za-z0-9_-]+\/attachments\/[A-Za-z0-9_-]+$/},{method:"GET",pattern:/^\/gmail\/v1\/users\/me\/labels$/},{method:"POST",pattern:/^\/gmail\/v1\/users\/me\/messages\/batchModify$/},{method:"POST",pattern:/^\/gmail\/v1\/users\/me\/messages\/batchDelete$/},{method:"POST",pattern:/^\/gmail\/v1\/users\/me\/messages\/send$/},{method:"POST",pattern:/^\/gmail\/v1\/users\/me\/messages\/[A-Za-z0-9_-]+\/(?:trash|untrash)$/}],Yt=new Set(["q","maxResults","pageToken","format","metadataHeaders","fields"]);async function Ye(e){let t=await Z(e.identity,e.connectionId);if(t.providerConfigKey!=="google-mail")throw new w("Service connection not found.",404,"connection_not_found",!1);if(!Wt.some(c=>c.method===e.method&&c.pattern.test(e.path)))throw new w("The Gmail provider operation is not allowed.",403,"tool_not_allowed",!1);if(Object.keys(e.query??{}).some(c=>!Yt.has(c)))throw new w("The Gmail provider query is not allowed.",400,"invalid_request",!1);let n=e.method==="POST";if(n&&!t.actionsEnabled)throw new w("Actions are disabled for this service connection.",403,"actions_disabled",!1);await he({identity:e.identity,ratePolicyVersion:C});let i=e.requestId?.trim()||He(),r=`main-gmail-proxy:${D("sha256").update(e.identity.toLowerCase()).update("\0").update(t.id).update("\0").update(e.method).update("\0").update(e.path).update("\0").update(i).digest("hex")}`,o=performance.now(),a,s;try{a=await P(`/proxy${e.path}`,{method:e.method,query:e.query,body:e.body,headers:{"connection-id":t.upstreamConnectionId,"provider-config-key":"google-mail","base-url-override":"https://gmail.googleapis.com"}})}catch(c){s=c}if(await we({identity:e.identity,idempotencyKey:r,ratePolicyVersion:C,connectionId:t.id,providerConfigKey:t.providerConfigKey,functionRuns:0,proxyRequests:1,computeMilliseconds:Math.max(0,Math.round(performance.now()-o)),sourceSurface:"main_mcp",metadata:{operationKind:n?"action":"read",outcome:s?"error":"success",requestId:i.length<=200?i:D("sha256").update(i).digest("hex")}}),s)throw Xe(s);return a}async function Qt(e){let t=(n,i,r)=>k({...e,path:n,query:i,baseUrlOverride:r});try{if(e.providerConfigKey==="google-mail"){let n=g(await t("/gmail/v1/users/me/profile",void 0,"https://gmail.googleapis.com")),i=O(n?.emailAddress);return T({id:i,email:i,name:null})}if(e.providerConfigKey==="google-drive"){let n=g(await t("/drive/v3/about",{fields:"user(permissionId,displayName,emailAddress)"},"https://www.googleapis.com")),i=g(n?.user);return T({id:m(i?.permissionId),email:O(i?.emailAddress),name:m(i?.displayName)})}if(e.providerConfigKey==="google-calendar"){let n=g(await t("/calendar/v3/calendars/primary",void 0,"https://www.googleapis.com")),i=m(n?.id);return T({id:i,email:O(i),name:m(n?.summary)})}if(e.providerConfigKey==="youtube"){let n=g(await t("/youtube/v3/channels",{part:"snippet",mine:"true",maxResults:1},"https://www.googleapis.com")),i=Array.isArray(n?.items)?g(n.items[0]):null;return T({id:m(i?.id),email:null,name:m(g(i?.snippet)?.title)})}}catch{}try{let n=g(await t("/v1/userinfo",void 0,"https://openidconnect.googleapis.com"));return T({id:m(n?.sub),email:n?.email_verified===!1?null:O(n?.email),name:m(n?.name)})}catch{return null}}async function Zt(e){if(!Xt.has(e.providerConfigKey))return null;if(e.providerConfigKey.startsWith("google-")||e.providerConfigKey==="youtube")return Qt(e);try{if(e.providerConfigKey==="github-getting-started"){let t=g(await k({...e,path:"/user"}));return T({id:Vt(t?.id),email:O(t?.email),name:m(t?.name)??m(t?.login)})}if(e.providerConfigKey==="slack"){let t=g(await k({...e,path:"/api/auth.test"}));return T({id:m(t?.user_id),email:null,name:[m(t?.user),m(t?.team)].filter(Boolean).join(" \xB7 ")||null})}if(e.providerConfigKey==="zoom"){let t=g(await k({...e,path:"/v2/users/me"})),n=[m(t?.first_name),m(t?.last_name)].filter(Boolean).join(" ");return T({id:m(t?.id),email:O(t?.email),name:m(t?.display_name)??(n||null)})}if(e.providerConfigKey==="linkedin"){let t=g(await k({...e,path:"/v2/userinfo"}));return T({id:m(t?.sub),email:t?.email_verified===!1?null:O(t?.email),name:m(t?.name)})}if(e.providerConfigKey==="meta-marketing-api"||e.providerConfigKey==="facebook"){let t=g(await k({...e,path:"/me",query:{fields:"id,name,email"}}));return T({id:m(t?.id),email:O(t?.email),name:m(t?.name)})}if(e.providerConfigKey==="twitter-v2"){let t=g(await k({...e,path:"/2/users/me",query:{"user.fields":"id,name,username"}})),n=g(t?.data);return T({id:m(n?.id),email:null,name:m(n?.username)??m(n?.name)})}if(e.providerConfigKey==="xero"){let t=await k({...e,path:"/connections"}),n=Array.isArray(t)?g(t[0]):null;return T({id:m(n?.tenantId),email:null,name:m(n?.tenantName)})}}catch{return null}return null}async function Gn(e,t={}){let n=[];for(let s=0;s<Lt;s+=1){let c=await P("/connections",{query:{limit:Fe,page:s}}),d=be(c,"connections");if(n.push(...d),d.length<Fe)break}let i=n.filter(s=>zt(s,e)).map(Jt).filter(s=>s!==null),o=(await de(e,i)).filter(s=>!Q(s.providerConfigKey));if(t.resolveProviderIdentity===!1)return o;let a=new Map(i.map(s=>[`${s.providerConfigKey}\0${s.upstreamConnectionId}`,s]));return await Promise.all(o.map(async s=>{if(s.lifecycleStatus!=="connected"||!s.upstreamConnectionId)return;let c=a.get(`${s.providerConfigKey}\0${s.upstreamConnectionId}`);if(!c)return;let d=c.updatedAt??c.createdAt??s.lifecycleStatus,l=!!(s.providerAccountId||s.providerAccountEmail||s.providerAccountName),u=s.providerIdentityCheckedAt?Date.parse(`${s.providerIdentityCheckedAt.replace(" ","T")}Z`):Number.NaN,p=!l&&Number.isFinite(u)&&Date.now()-u<Kt;if(s.providerIdentitySourceUpdatedAt===d&&(l||p))return;let _=await Zt({upstreamConnectionId:s.upstreamConnectionId,providerConfigKey:s.providerConfigKey});await Ue({connectionId:s.id,providerAccountId:_?.id,providerAccountEmail:_?.email,providerAccountName:_?.name,sourceUpdatedAt:d})})),(await de(e,i)).filter(s=>!Q(s.providerConfigKey))}async function Dn(){let[e,t]=await Promise.all([P("/integrations"),P("/providers")]),n=new Map;for(let i of be(t,"providers")){let r=g(i),o=m(r?.name);r&&o&&n.set(o,r)}return be(e,"integrations").flatMap(i=>{let r=g(i),o=m(r?.unique_key)??m(r?.id),a=m(r?.provider);if(!o||!a||Q(o))return[];let s=n.get(a);return[{id:o,provider:a,displayName:m(r?.display_name)??m(s?.display_name)??o,authMode:m(s?.auth_mode),categories:Array.isArray(s?.categories)?s.categories:[],docsUrl:m(s?.docs),logoUrl:m(r?.logo),safeDefaultAllowedTools:[],actionTools:[],setupStatus:"ready"}]})}function Qe(e){let n={linkedin:"openid profile email w_member_social","github-getting-started":"repo workflow read:org read:user user:email","google-drive":"openid profile email https://www.googleapis.com/auth/drive","google-search-console":"openid profile email https://www.googleapis.com/auth/webmasters.readonly https://www.googleapis.com/auth/webmasters"}[e];return n?{[e]:{connection_config:{oauth_scopes_override:n}}}:void 0}function Ze(e){let t=g(e),n=g(t?.data)??t,i=m(n?.connect_link);if(!i)throw new w("Nango did not return a connect link.",502,"nango_missing_connect_link");return{connectLink:i,expiresAt:m(n?.expires_at)}}async function Un(e,t){ze(t);let n=Qe(t);return Ze(await P("/connect/sessions",{method:"POST",body:{tags:{end_user_id:e,end_user_email:e},allowed_integrations:[t],...n?{integrations_config_defaults:n}:{}}}))}async function qn(e,t){let n=await Z(e,t,!0),i=Qe(n.providerConfigKey);return Ze(await P("/connect/sessions/reconnect",{method:"POST",body:{connection_id:n.upstreamConnectionId,integration_id:n.providerConfigKey,tags:{end_user_id:e,end_user_email:e},...i?{integrations_config_defaults:i}:{}}}))}async function Ln(e,t){let n=await et(e,t);try{await P(`/connections/${encodeURIComponent(n.upstreamConnectionId)}`,{method:"DELETE",query:{provider_config_key:n.providerConfigKey}})}catch(i){if(!(i instanceof w)||i.status!==404)throw i}}async function et(e,t){let n=await le(e,t);if(!n||n.transport!=="nango"||!n.upstreamConnectionId)throw new w("Service connection not found.",404,"connection_not_found",!1);return n}async function Z(e,t,n=!1){let i=await et(e,t);if(ze(i.providerConfigKey),i.lifecycleStatus!=="connected"&&!(n&&i.lifecycleStatus==="needs_reauth"))throw new w("Service connection requires reconnection.",409,"connection_inactive",!1);return i}async function ve(e,t){let n=new Gt(We(),{requestInit:{headers:{Authorization:`Bearer ${Ve()}`,"connection-id":e.upstreamConnectionId,"provider-config-key":e.providerConfigKey}}}),i=new Mt({name:"mcp-scraper-integrations",version:"1.0.0"},{capabilities:{}});try{await i.connect(n);let r=await t(i);return await ue({connectionId:e.id,operationalStatus:"available",evidenceSource:"nango_mcp"}),r}catch(r){let o=Xe(r);throw await ue({connectionId:e.id,operationalStatus:o.code==="connection_transport_unavailable"?"unavailable":"degraded",failureCode:o.code,retryable:o.retryable,evidenceSource:"nango_mcp"}).catch(()=>{}),o}finally{await i.close().catch(()=>{})}}async function Kn(e,t){let n=await Z(e,t);(n.provider??n.providerConfigKey)==="google-search-console"&&await ve(n,async r=>{if(!(await r.listTools()).tools.some(a=>a.name==="list-sites"))throw new w("The Search Console health-check tool is unavailable.",404,"live_tool_missing",!1);await r.callTool({name:"list-sites",arguments:{}})})}async function tt(e,t){let n=await Z(e,t),r=(await ve(n,l=>l.listTools())).tools.flatMap(l=>{let u=g(l.inputSchema);return!l.name||!u?[]:[{name:l.name,...l.title?{title:l.title}:{},...l.description?{description:l.description}:{},inputSchema:u,...g(l.outputSchema)?{outputSchema:g(l.outputSchema)}:{},...g(l.annotations)?{annotations:g(l.annotations)}:{}}]}),o=Y({tools:r,connectionActive:n.lifecycleStatus==="connected",actionsEnabled:n.actionsEnabled}),a=[...o.values()].filter(l=>l.classification==="read").map(l=>l.name),s=[...o.values()].filter(l=>l.classification==="action").map(l=>l.name),c=D("sha256").update(JSON.stringify(r.map(l=>({name:l.name,inputSchema:l.inputSchema})))).digest("hex");return await De(n.id,a,s,c),{connection:await le(e,n.id)??{...n,readTools:a,actionTools:s,toolRevision:c},tools:r}}async function $n(e){let{connection:t,tools:n}=await tt(e.identity,e.connectionId),i=n.find(p=>p.name===e.tool);if(!i)throw new w("The requested provider tool is unavailable.",404,"live_tool_missing",!1);let r=Ie(Y({tools:n,connectionActive:t.lifecycleStatus==="connected",actionsEnabled:t.actionsEnabled}),i.name);if(r.classification!==e.classification)throw new w("The provider tool classification does not match this operation.",403,"tool_not_allowed",!1);if(!r.available&&r.blockedReason==="actions_disabled")throw new w("Actions are disabled for this service connection.",403,"actions_disabled",!1);if(!r.available)throw new w("The provider tool is not authorized for this connection.",403,"tool_not_allowed",!1);await he({identity:e.identity,ratePolicyVersion:C});let o=e.requestId?.trim()||He(),a=`main-nango:${D("sha256").update(e.identity.toLowerCase()).update("\0").update(t.id).update("\0").update(e.tool).update("\0").update(o).digest("hex")}`,s=new Date,c=performance.now(),d,l;try{d=await ve(t,p=>Ht(p,e.tool,e.input))}catch(p){l=p}let u=new Date;if(await we({identity:e.identity,idempotencyKey:a,ratePolicyVersion:C,connectionId:t.id,providerConfigKey:t.providerConfigKey,functionRuns:1,proxyRequests:0,computeMilliseconds:Math.max(0,Math.round(performance.now()-c)),sourceSurface:"main_mcp",metadata:{toolName:e.tool,operationKind:e.operationKind??e.classification,outcome:l?"error":"partial",requestId:o.length<=200?o:D("sha256").update(o).digest("hex"),startedAt:s.toISOString(),completedAt:u.toISOString()}}),l)throw l;return d}async function jn(e,t,n){let{connection:i,tools:r}=await tt(e,t),o=r.find(l=>l.name===n);if(!o)throw new w("The requested provider tool is unavailable.",404,"live_tool_missing",!1);let a=Ie(Y({tools:r,connectionActive:i.lifecycleStatus==="connected",actionsEnabled:i.actionsEnabled}),o.name),s=_e(o),c=a.available,d={name:o.name,...o.title?{title:o.title}:{},...o.description?{description:o.description}:{},inputSchema:o.inputSchema,...o.outputSchema?{outputSchema:o.outputSchema}:{},...o.annotations?{annotations:o.annotations}:{}};return{...d,classification:s,callable:c,blockedReason:a.blockedReason,requiredPermissions:a.requiredPermissions,missingPermissions:a.missingPermissions,requiredFeatures:a.requiredFeatures,missingFeatures:a.missingFeatures,transport:"nango",providerConfigKey:i.providerConfigKey,providerContractVersion:jt,providerContractHash:Bt,protocolVersion:null,schemaSource:"live_tools_list",schemaHash:D("sha256").update(JSON.stringify(d)).digest("hex"),fetchedAt:new Date().toISOString()}}import{createHash as en,randomUUID as ot}from"crypto";var tn=1440*60*1e3,nt=5e3,S=class extends Error{constructor(n,i,r=400){super(i);this.code=n;this.status=r;this.name="GmailSelectionError"}code;status},j=null,Se=null;function Ce(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(Ce).join(",")}]`:`{${Object.entries(e).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>`${JSON.stringify(t)}:${Ce(n)}`).join(",")}}`}function U(e){return en("sha256").update(Ce(e)).digest("hex")}async function A(){let e=y();return j&&Se===e||(Se=e,j=(async()=>{await e.execute(`
|
|
20
|
+
CREATE TABLE IF NOT EXISTS gmail_selections (
|
|
21
|
+
selection_id TEXT PRIMARY KEY,
|
|
22
|
+
owner_identity TEXT NOT NULL,
|
|
23
|
+
connection_id TEXT NOT NULL,
|
|
24
|
+
purpose TEXT NOT NULL,
|
|
25
|
+
source_json TEXT NOT NULL,
|
|
26
|
+
message_ids_json TEXT NOT NULL,
|
|
27
|
+
message_count INTEGER NOT NULL,
|
|
28
|
+
selection_sha256 TEXT NOT NULL,
|
|
29
|
+
provider_snapshot_json TEXT,
|
|
30
|
+
created_at TEXT NOT NULL,
|
|
31
|
+
expires_at TEXT NOT NULL,
|
|
32
|
+
UNIQUE(owner_identity, connection_id, purpose, selection_sha256)
|
|
33
|
+
)
|
|
34
|
+
`),await e.execute("CREATE INDEX IF NOT EXISTS gmail_selections_owner_expiry ON gmail_selections(owner_identity, expires_at)"),await e.execute(`
|
|
35
|
+
CREATE TABLE IF NOT EXISTS gmail_action_executions (
|
|
36
|
+
action_id TEXT PRIMARY KEY,
|
|
37
|
+
owner_identity TEXT NOT NULL,
|
|
38
|
+
idempotency_key TEXT NOT NULL,
|
|
39
|
+
fingerprint TEXT NOT NULL,
|
|
40
|
+
status TEXT NOT NULL,
|
|
41
|
+
result_json TEXT,
|
|
42
|
+
created_at TEXT NOT NULL,
|
|
43
|
+
updated_at TEXT NOT NULL,
|
|
44
|
+
UNIQUE(owner_identity, idempotency_key)
|
|
45
|
+
)
|
|
46
|
+
`),await e.execute("CREATE INDEX IF NOT EXISTS gmail_actions_owner_updated ON gmail_action_executions(owner_identity, updated_at)"),await e.execute(`CREATE TABLE IF NOT EXISTS gmail_action_chunks (
|
|
47
|
+
action_id TEXT NOT NULL, chunk_key TEXT NOT NULL, status TEXT NOT NULL,
|
|
48
|
+
result_json TEXT, updated_at TEXT NOT NULL,
|
|
49
|
+
PRIMARY KEY(action_id, chunk_key)
|
|
50
|
+
)`),await e.execute(`CREATE TABLE IF NOT EXISTS gmail_selection_exports (
|
|
51
|
+
selection_id TEXT PRIMARY KEY, owner_identity TEXT NOT NULL, fingerprint TEXT NOT NULL,
|
|
52
|
+
status TEXT NOT NULL, result_json TEXT, updated_at TEXT NOT NULL
|
|
53
|
+
)`)})().catch(t=>{throw j=null,Se=null,t})),j}function it(e){let t=[...new Set(e.map(n=>n.trim()).filter(n=>/^[A-Za-z0-9_-]+$/.test(n)))];return t.sort(),t}function rt(e){return{selectionId:String(e.selection_id),ownerId:String(e.owner_identity),connectionId:String(e.connection_id),purpose:String(e.purpose),source:JSON.parse(String(e.source_json)),messageIds:JSON.parse(String(e.message_ids_json)),count:Number(e.message_count),selectionSha256:String(e.selection_sha256),createdAt:String(e.created_at),expiresAt:String(e.expires_at),providerSnapshot:typeof e.provider_snapshot_json=="string"?JSON.parse(e.provider_snapshot_json):null}}async function at(e){await A();let t=it(e.resolvedMessageIds);if(t.length===0)throw new S("selection_empty","No Gmail messages matched the selection.");if(t.length>nt)throw new S("selection_too_large",`Narrow the Gmail selection to at most ${nt} messages.`);let n=e.source.kind==="query"?{kind:"query",query:e.source.query.trim().replace(/\s+/g," ")}:{kind:"message_ids",messageIds:it(e.source.messageIds)},i=U({connectionId:e.connectionId,purpose:e.purpose,source:n,messageIds:t}),r=await y().execute({sql:"SELECT * FROM gmail_selections WHERE owner_identity = ? AND connection_id = ? AND purpose = ? AND selection_sha256 = ? AND expires_at > ? LIMIT 1",args:[e.ownerId,e.connectionId,e.purpose,i,(e.now??new Date).toISOString()]});if(r.rows[0])return rt(r.rows[0]);let o=e.now??new Date,a={selectionId:`gsel_${ot().replace(/-/g,"")}`,ownerId:e.ownerId,connectionId:e.connectionId,purpose:e.purpose,source:n,messageIds:t,count:t.length,selectionSha256:i,createdAt:o.toISOString(),expiresAt:new Date(o.getTime()+tn).toISOString(),providerSnapshot:e.providerSnapshot??null};return await y().execute({sql:"INSERT INTO gmail_selections (selection_id, owner_identity, connection_id, purpose, source_json, message_ids_json, message_count, selection_sha256, provider_snapshot_json, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",args:[a.selectionId,a.ownerId,a.connectionId,a.purpose,JSON.stringify(a.source),JSON.stringify(a.messageIds),a.count,a.selectionSha256,a.providerSnapshot?JSON.stringify(a.providerSnapshot):null,a.createdAt,a.expiresAt]}),a}async function ee(e){await A();let n=(await y().execute({sql:"SELECT * FROM gmail_selections WHERE selection_id = ? AND owner_identity = ? AND connection_id = ? AND expires_at > ? LIMIT 1",args:[e.selectionId,e.ownerId,e.connectionId,(e.now??new Date).toISOString()]})).rows[0];if(!n)throw new S("selection_not_found","Gmail selection not found.",404);return rt(n)}function te(e,t,n){if(t!==e.count||n!==e.selectionSha256)throw new S("selection_changed","The Gmail selection receipt does not match the immutable selection.",409)}function xe(e){return{actionId:String(e.action_id),ownerId:String(e.owner_identity),idempotencyKey:String(e.idempotency_key),fingerprint:String(e.fingerprint),status:String(e.status),result:typeof e.result_json=="string"?JSON.parse(e.result_json):null,createdAt:String(e.created_at),updatedAt:String(e.updated_at)}}async function ne(e){await A();let t=e.idempotencyKey.trim();if(t.length<8||t.length>200)throw new S("idempotency_key_invalid","Idempotency-Key must be 8-200 characters.");let n=await y().execute({sql:"SELECT * FROM gmail_action_executions WHERE owner_identity = ? AND idempotency_key = ? LIMIT 1",args:[e.ownerId,t]});if(n.rows[0]){let o=xe(n.rows[0]);if(o.fingerprint!==e.fingerprint)throw new S("idempotency_conflict","This Idempotency-Key is already bound to a different Gmail action.",409);if(o.status==="running"&&!o.result&&Date.now()-Date.parse(o.updatedAt)>6e4){let a=new Date().toISOString(),s=await y().execute({sql:"UPDATE gmail_action_executions SET updated_at = ? WHERE action_id = ? AND updated_at = ?",args:[a,o.actionId,o.updatedAt]});if(Number(s.rowsAffected??0)===1)return{execution:{...o,updatedAt:a},replay:!1}}return{execution:o,replay:!0}}let i=new Date().toISOString(),r={actionId:`gact_${ot().replace(/-/g,"")}`,ownerId:e.ownerId,idempotencyKey:t,fingerprint:e.fingerprint,status:"running",result:null,createdAt:i,updatedAt:i};try{await y().execute({sql:"INSERT INTO gmail_action_executions (action_id, owner_identity, idempotency_key, fingerprint, status, created_at, updated_at) VALUES (?, ?, ?, ?, 'running', ?, ?)",args:[r.actionId,r.ownerId,r.idempotencyKey,r.fingerprint,i,i]})}catch{let o=await y().execute({sql:"SELECT * FROM gmail_action_executions WHERE owner_identity = ? AND idempotency_key = ? LIMIT 1",args:[e.ownerId,t]});if(!o.rows[0])throw new S("action_claim_failed","The Gmail action could not be claimed.",409);let a=xe(o.rows[0]);if(a.fingerprint!==e.fingerprint)throw new S("idempotency_conflict","This Idempotency-Key is already bound to a different Gmail action.",409);return{execution:a,replay:!0}}return{execution:r,replay:!1}}async function ie(e){await A(),await y().execute({sql:"UPDATE gmail_action_executions SET updated_at = ? WHERE action_id = ? AND status = 'running'",args:[new Date().toISOString(),e]})}function nn(e){return{actionId:String(e.action_id),chunkKey:String(e.chunk_key),status:String(e.status),result:typeof e.result_json=="string"?JSON.parse(e.result_json):null,updatedAt:String(e.updated_at)}}async function B(e,t){await A();let n=new Date().toISOString();try{return await y().execute({sql:"INSERT INTO gmail_action_chunks (action_id, chunk_key, status, updated_at) VALUES (?, ?, 'running', ?)",args:[e,t,n]}),{receipt:{actionId:e,chunkKey:t,status:"running",result:null,updatedAt:n},claimed:!0}}catch{let i=await y().execute({sql:"SELECT * FROM gmail_action_chunks WHERE action_id = ? AND chunk_key = ? LIMIT 1",args:[e,t]});if(!i.rows[0])throw new S("action_chunk_claim_failed","The Gmail action chunk could not be claimed.",409);return{receipt:nn(i.rows[0]),claimed:!1}}}async function N(e,t,n,i){await A(),await y().execute({sql:"UPDATE gmail_action_chunks SET status = ?, result_json = ?, updated_at = ? WHERE action_id = ? AND chunk_key = ?",args:[n,JSON.stringify(i),new Date().toISOString(),e,t]})}async function st(e){await A();let t=await y().execute({sql:"SELECT * FROM gmail_selection_exports WHERE selection_id = ? AND owner_identity = ? LIMIT 1",args:[e.selectionId,e.ownerId]});if(t.rows[0]){let n=t.rows[0];if(String(n.fingerprint)!==e.fingerprint)throw new S("export_conflict","This Gmail selection export receipt conflicts with the stored export.",409);let i=typeof n.result_json=="string"?JSON.parse(n.result_json):null;if(i)return{replay:i,claimed:!1};if(Date.now()-Date.parse(String(n.updated_at))>5*6e4){let r=await y().execute({sql:"UPDATE gmail_selection_exports SET updated_at = ? WHERE selection_id = ? AND owner_identity = ? AND updated_at = ?",args:[new Date().toISOString(),e.selectionId,e.ownerId,String(n.updated_at)]});if(Number(r.rowsAffected??0)===1)return{replay:null,claimed:!0}}return{replay:null,claimed:!1}}try{return await y().execute({sql:"INSERT INTO gmail_selection_exports (selection_id, owner_identity, fingerprint, status, updated_at) VALUES (?, ?, ?, 'running', ?)",args:[e.selectionId,e.ownerId,e.fingerprint,new Date().toISOString()]}),{replay:null,claimed:!0}}catch{let n=await y().execute({sql:"SELECT * FROM gmail_selection_exports WHERE selection_id = ? AND owner_identity = ? LIMIT 1",args:[e.selectionId,e.ownerId]});if(!n.rows[0])throw new S("export_claim_failed","The Gmail export could not be claimed.",409);let i=n.rows[0];if(String(i.fingerprint)!==e.fingerprint)throw new S("export_conflict","This Gmail selection export receipt conflicts with the stored export.",409);return{replay:typeof i.result_json=="string"?JSON.parse(i.result_json):null,claimed:!1}}}async function ct(e,t,n){await A(),await y().execute({sql:"UPDATE gmail_selection_exports SET status = 'complete', result_json = ?, updated_at = ? WHERE selection_id = ? AND owner_identity = ?",args:[JSON.stringify(n),new Date().toISOString(),t,e]})}async function F(e,t,n){await A();let i=new Date().toISOString();await y().execute({sql:"UPDATE gmail_action_executions SET status = ?, result_json = ?, updated_at = ? WHERE action_id = ?",args:[t,JSON.stringify(n),i,e]});let r=await y().execute({sql:"SELECT * FROM gmail_action_executions WHERE action_id = ? LIMIT 1",args:[e]});if(!r.rows[0])throw new S("action_not_found","Gmail action not found.",404);return xe(r.rows[0])}var rn="2026-08-27.1",Qn="9c82b270bb70e7795814cac408a41786ec70d4d7a4bb0f4a11bcc1b7fd02088b",H=2e4,an=10080*60*1e3,f=class extends Error{constructor(n,i,r=400,o=r===429||r>=500,a=null){super(i);this.code=n;this.status=r;this.retryable=o;this.retryAfterMs=a;this.name="GmailServiceError"}code;status;retryable;retryAfterMs};function v(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function h(e){return typeof e=="string"&&e.length>0?e:null}function q(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function J(e){if(!/^[A-Za-z0-9_-]*={0,2}$/.test(e))throw new f("gmail_invalid_base64","Gmail returned invalid encoded content.",502);let t=e.replace(/-/g,"+").replace(/_/g,"/");return Buffer.from(t.padEnd(Math.ceil(t.length/4)*4,"="),"base64")}function sn(e){return/^[\x20-\x7e]*$/.test(e)?e:`=?UTF-8?B?${Buffer.from(e,"utf8").toString("base64")}?=`}function cn(e,t,n){let i=Buffer.from(n,"utf8").toString("base64").match(/.{1,76}/g)?.join(`\r
|
|
54
|
+
`)??"";return[`To: ${e}`,`Subject: ${sn(t)}`,"MIME-Version: 1.0","Content-Type: text/plain; charset=UTF-8","Content-Transfer-Encoding: base64","",i].join(`\r
|
|
55
|
+
`)}function ft(e){let t=e.toString("latin1").replace(/=\r?\n/g,""),n=[];for(let i=0;i<t.length;i++)t[i]==="="&&/^[0-9A-Fa-f]{2}$/.test(t.slice(i+1,i+3))?(n.push(Number.parseInt(t.slice(i+1,i+3),16)),i+=2):n.push(t.charCodeAt(i)&255);return Buffer.from(n)}function Ae(e){return e.replace(/=\?([^?]+)\?([bq])\?([^?]+)\?=/gi,(t,n,i,r)=>{try{let o=i.toLowerCase()==="b"?Buffer.from(r,"base64"):ft(Buffer.from(r.replace(/_/g," "),"latin1"));return/^(?:utf-8|us-ascii)$/i.test(n)?o.toString("utf8"):o.toString("latin1")}catch{return r}})}function dn(e){return Array.isArray(e)?e.flatMap(t=>{let n=v(t),i=h(n?.name),r=h(n?.value);return!i||r===null?[]:[{name:i,value:Ae(r.replace(/\r?\n[ \t]+/g," "))}]}):[]}function E(e,t){return e.find(n=>n.name.toLowerCase()===t.toLowerCase())?.value??null}function z(e){return e?(e.match(/(?:"(?:[^"\\]|\\.)*"|[^,])+/g)??[]).flatMap(n=>{let i=n.trim(),r=i.match(/^(.*?)\s*<([^<>\s]+@[^<>\s]+)>$/),o=(r?.[2]??i).replace(/^mailto:/i,"").trim().toLowerCase();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(o))return[];let a=r?.[1]?.trim().replace(/^"|"$/g,"")||null;return[{name:a?Ae(a):null,email:o}]}):[]}function ln(e,t){let n=J(e),i=E(t,"content-transfer-encoding")?.toLowerCase();if(i==="quoted-printable")return ft(n);if(i==="base64"){let r=n.toString("ascii").replace(/\s/g,"");return/^[A-Za-z0-9+/]*={0,2}$/.test(r)?Buffer.from(r,"base64"):n}return n}function un(e){return e.replace(/<!--[\s\S]*?-->/g,"").replace(/<!doctype\b[^>]*>/gi,"").replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi,"").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi,"").replace(/<(?:iframe|object|embed|svg|math)\b[^>]*>[\s\S]*?<\/(?:iframe|object|embed|svg|math)>/gi,"").replace(/<\/?(?:script|style|iframe|object|embed|svg|math|form|input|button|textarea|select|option|meta|link|base|img|audio|video|source|track)\b[^>]*>/gi,"").replace(/\son\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi,"").replace(/\s(?:href|src|srcset|action|formaction|poster|background|xlink:href)\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi,"").replace(/<[^>]*>/g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\s+/g," ").trim()}function gt(){return Te("sha256").update(Ge()).update("\0gmail-ref-v1").digest()}function yt(e){let t=Buffer.from(JSON.stringify(e)).toString("base64url"),n=pt("sha256",gt()).update(t).digest("base64url");return`gref1.${t}.${n}`}function dt(e,t,n){let[i,r,o]=e.split(".");if(i!=="gref1"||!r||!o)throw new f("reference_not_found","Gmail reference not found.",404,!1);let a=pt("sha256",gt()).update(r).digest(),s;try{s=Buffer.from(o,"base64url")}catch{throw new f("reference_not_found","Gmail reference not found.",404,!1)}if(a.length!==s.length||!on(a,s))throw new f("reference_not_found","Gmail reference not found.",404,!1);let c;try{c=JSON.parse(Buffer.from(r,"base64url").toString("utf8"))}catch{throw new f("reference_not_found","Gmail reference not found.",404,!1)}if(c.ownerId!==t||c.kind!==n||typeof c.expiresAt!="number"||c.expiresAt<=Date.now())throw new f("reference_not_found","Gmail reference not found.",404,!1);return c}function mn(e){return yt({kind:"attachment",...e,expiresAt:Date.now()+an})}function ht(e){let t=dn(e.part.headers),n=v(e.part.body),i=h(e.part.mimeType)?.toLowerCase()??"application/octet-stream",r=Ae(h(e.part.filename)??""),o=h(e.part.partId)??e.path,a=h(n?.data),s=h(n?.attachmentId),c=E(t,"content-id")?.replace(/^<|>$/g,"")??null,d=/^inline\b/i.test(E(t,"content-disposition")??"")||!!c,l=i.startsWith("text/"),u=null,p=!0;l&&a?u=ln(a,t).toString("utf8"):l&&s&&(p=!1);let _=!!r||!!s||d&&!!a&&!l,I=null,M=q(n?.size)??(a?J(a).byteLength:0);if(_){let L=M;I=mn({ownerId:e.ownerId,connectionId:e.connectionId,messageId:e.messageId,partId:o,attachmentId:s,filename:r||`gmail-${e.messageId}-${o}`,mimeType:i,size:L}),e.attachments.push({filename:r||`gmail-${e.messageId}-${o}`,declaredMime:i,size:L,inline:d,contentId:c,partId:o,attachmentRef:I})}let It=Array.isArray(e.part.parts)?e.part.parts.map((L,bt)=>ht({...e,part:v(L)??{},path:`${e.path}.${bt+1}`})):[];return{partId:o,mimeType:i,filename:r,headers:t,size:M,inline:d,contentId:c,contentComplete:p,text:u,attachmentRef:I,parts:It}}function Ee(e,t){return[...e.mimeType===t&&e.text!==null?[e.text]:[],...e.parts.flatMap(i=>Ee(i,t))]}function lt(e){let t=v(e.payload),n=h(t?.id),i=v(t?.payload);if(!n||!i)throw new f("gmail_invalid_message","Gmail returned an invalid message.",502);let r=[],o=ht({part:i,ownerId:e.ownerId,connectionId:e.connectionId,messageId:n,path:"0",attachments:r}),a=o.headers,s=Ee(o,"text/plain").join(`
|
|
56
|
+
`).trim()||null,c=Ee(o,"text/html").join(`
|
|
57
|
+
`).trim()||null;return{messageId:n,threadId:h(t?.threadId),messageIdHeader:E(a,"message-id"),internalDate:h(t?.internalDate)?new Date(Number(t.internalDate)).toISOString():null,headers:a,from:z(E(a,"from")),to:z(E(a,"to")),cc:z(E(a,"cc")),bcc:z(E(a,"bcc")),replyTo:z(E(a,"reply-to")),subject:E(a,"subject"),labels:Array.isArray(t?.labelIds)?t.labelIds.filter(d=>typeof d=="string"):[],snippet:h(t?.snippet),plainText:s,sanitizedHtml:c?un(c):null,contentComplete:wt(o),providerSizeEstimate:q(t?.sizeEstimate),mime:o,attachments:r,provenance:{provider:"gmail",connectionId:e.connectionId,fetchedAt:(e.fetchedAt??new Date).toISOString(),format:"full"}}}function wt(e){return e.contentComplete&&e.parts.every(wt)}var ut=class{providerCall;createArtifact;createJsonlArtifact;constructor(t={}){this.providerCall=t.providerCall??Ye,this.createArtifact=t.createArtifact??Me,this.createJsonlArtifact=t.createJsonlArtifact??Pe}async sendMessage(t){let n=t.to.trim().toLowerCase(),i=t.subject.trim();if(!/^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(n)||/[\r\n]/.test(t.to))throw new f("invalid_request","A valid recipient email address is required.");if(!i||i.length>500||/[\r\n]/.test(i))throw new f("invalid_request","A subject of at most 500 characters without line breaks is required.");if(!t.body||t.body.length>5e4)throw new f("invalid_request","A plain-text body of at most 50,000 characters is required.");if(t.idempotencyKey.length<8||t.idempotencyKey.length>200)throw new f("idempotency_key_invalid","Idempotency key must contain 8-200 characters.");let r=U({connectionId:t.connectionId,to:n,subject:i,bodySha256:Te("sha256").update(t.body).digest("hex")}),o=await ne({ownerId:t.ownerId,idempotencyKey:t.idempotencyKey,fingerprint:r});if(o.replay&&o.execution.result)return{...o.execution.result,replay:!0};if(o.replay)return{actionId:o.execution.actionId,status:"outcome_unknown",replay:!0,retryable:!1};let a=await B(o.execution.actionId,"send:0");if(!a.claimed)return{...a.receipt.result??{},actionId:o.execution.actionId,status:a.receipt.status,replay:!0};try{let s=v(await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"POST",path:"/gmail/v1/users/me/messages/send",body:{raw:Buffer.from(cn(n,i,t.body),"utf8").toString("base64url")},requestId:t.idempotencyKey})),c={actionId:o.execution.actionId,status:"complete",messageId:h(s?.id),threadId:h(s?.threadId),replay:!1};return await N(o.execution.actionId,"send:0","complete",c),await F(o.execution.actionId,"complete",c),c}catch(s){let c={actionId:o.execution.actionId,status:"outcome_unknown",code:oe(s),retryable:!1};throw await N(o.execution.actionId,"send:0","failed",c),await F(o.execution.actionId,"partial",c),s}}async searchMessages(t){let n=t.query.trim();if(!n||n.length>2e3)throw new f("invalid_request","A Gmail query of at most 2,000 characters is required.");let i=t.limit??25;if(!Number.isInteger(i)||i<1||i>500)throw new f("invalid_request","Gmail search limit must be an integer from 1 to 500.");let r=i,o;if(t.cursor){let d=dt(t.cursor,t.ownerId,"search_cursor");if(d.connectionId!==t.connectionId||d.query!==n)throw new f("cursor_not_found","Gmail cursor not found.",404,!1);o=h(d.pageToken)??void 0}let a=v(await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"GET",path:"/gmail/v1/users/me/messages",query:{q:n,maxResults:r,pageToken:o}})),s=Array.isArray(a?.messages)?a.messages.flatMap(d=>{let l=v(d),u=h(l?.id);return u?[{messageId:u,threadId:h(l?.threadId)}]:[]}):[],c=h(a?.nextPageToken);return{messages:s,estimatedMatches:q(a?.resultSizeEstimate),complete:!c,truncated:!!c,nextCursor:c?yt({kind:"search_cursor",ownerId:t.ownerId,connectionId:t.connectionId,query:n,pageToken:c,expiresAt:Date.now()+1440*60*1e3}):null}}async getMessage(t){let n=await this.getCompleteMessage(t),i=!!n.canonicalArtifact,r=n.plainText&&Buffer.byteLength(n.plainText)>H?`${Buffer.from(n.plainText).subarray(0,H).toString("utf8")}\u2026`:n.plainText;return{...n,plainText:r,contentComplete:n.contentComplete&&!i}}async getCompleteMessage(t){if(!/^[A-Za-z0-9_-]+$/.test(t.messageId))throw new f("invalid_request","A valid Gmail message ID is required.");let n=encodeURIComponent(t.messageId),i=t.providerIdentity??t.ownerId,r=await this.providerCall({identity:i,connectionId:t.connectionId,method:"GET",path:`/gmail/v1/users/me/messages/${n}`,query:{format:"full"}}),o=lt({ownerId:t.ownerId,connectionId:t.connectionId,payload:r}),a=null;if(t.includeRawArtifact!==!1){let l=v(await this.providerCall({identity:i,connectionId:t.connectionId,method:"GET",path:`/gmail/v1/users/me/messages/${n}`,query:{format:"raw"}})),u=h(l?.raw);if(!u)throw new f("gmail_raw_unavailable","Gmail did not return the raw message.",502);a=await this.createArtifact({ownerId:t.ownerId,exportId:`gmail-raw-${t.messageId}`,filename:`${t.messageId}.eml`,content:J(u),contentType:"message/rfc822"})}let s=JSON.stringify(o),d=Buffer.byteLength(s)>H||!o.contentComplete?await this.createArtifact({ownerId:t.ownerId,exportId:`gmail-message-${t.messageId}`,filename:`${t.messageId}.json`,content:s,contentType:"application/json"}):null;return{...o,rawArtifact:a,canonicalArtifact:d}}async getAttachment(t){let n=dt(t.attachmentRef,t.ownerId,"attachment"),i=h(n.connectionId),r=h(n.messageId);if(!i||!r)throw new f("reference_not_found","Gmail reference not found.",404,!1);let o,a=h(n.attachmentId);if(a){let _=v(await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:i,method:"GET",path:`/gmail/v1/users/me/messages/${encodeURIComponent(r)}/attachments/${encodeURIComponent(a)}`})),I=h(_?.data);if(!I)throw new f("gmail_attachment_unavailable","Gmail did not return attachment bytes.",502);o=J(I);let M=q(_?.size);if(M!==null&&M!==o.byteLength)throw new f("gmail_attachment_size_mismatch","Gmail attachment bytes did not match the declared size.",502)}else{let _=v(await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:i,method:"GET",path:`/gmail/v1/users/me/messages/${encodeURIComponent(r)}`,query:{format:"full"}})),I=_t(v(_?.payload),h(n.partId)??"");if(!I)throw new f("reference_not_found","Gmail reference not found.",404,!1);o=J(I)}let s=h(n.mimeType)??"application/octet-stream",c=q(n.size);if(c!==null&&c>0&&c!==o.byteLength)throw new f("gmail_attachment_size_mismatch","Gmail attachment bytes did not match the reviewed MIME part size.",502);let d=gn(o,s),l=h(n.filename)??`gmail-${r}.bin`,u=await this.createArtifact({ownerId:t.ownerId,exportId:`gmail-attachment-${r}`,filename:l,content:o,contentType:d}),p=d.startsWith("text/")||d==="application/json"?o.subarray(0,H).toString("utf8"):null;return{filename:l,declaredMime:s,observedMime:d,bytes:o.byteLength,sha256:Te("sha256").update(o).digest("hex"),contentComplete:p!==null?o.byteLength<=H:!0,text:p,artifact:u}}async prepareSelection(t){let n,i=null;if(t.source.kind==="message_ids"){if(!t.source.messageIds.length||t.source.messageIds.some(r=>typeof r!="string"||!/^[A-Za-z0-9_-]+$/.test(r.trim())))throw new f("invalid_request","Every explicit Gmail message ID must be valid.");n=[...new Set(t.source.messageIds.map(r=>r.trim()))];for(let r of n)try{await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"GET",path:`/gmail/v1/users/me/messages/${encodeURIComponent(r)}`,query:{format:"metadata"}})}catch{throw new f("selection_message_not_found","One or more explicit Gmail message IDs do not exist in this connection.",404,!1)}}else{n=[];let r,o=null;do{let a=v(await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"GET",path:"/gmail/v1/users/me/messages",query:{q:t.source.query.trim(),maxResults:500,pageToken:r}}));o===null&&(o=q(a?.resultSizeEstimate));for(let s of Array.isArray(a?.messages)?a.messages:[]){let c=h(v(s)?.id);c&&n.push(c)}if(new Set(n).size>5e3)throw new f("selection_too_large","Narrow the Gmail selection to at most 5,000 messages.");r=h(a?.nextPageToken)??void 0}while(r);if(t.exactRange){let a=Date.parse(t.exactRange.from),s=Date.parse(t.exactRange.to);if(!Number.isFinite(a)||!Number.isFinite(s)||a>=s)throw new f("invalid_request","exactRange.from must be before exactRange.to.");let c=[];for(let d of n){let l=await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"GET",path:`/gmail/v1/users/me/messages/${encodeURIComponent(d)}`,query:{format:"full"}}),u=lt({ownerId:t.ownerId,connectionId:t.connectionId,payload:l}),p=u.internalDate?Date.parse(u.internalDate):Number.NaN;Number.isFinite(p)&&p>=a&&p<s&&c.push(d)}n=c}i={estimatedMatches:o,pagesComplete:!0,...t.exactRange?{exactRange:t.exactRange}:{}}}return at({ownerId:t.ownerId,connectionId:t.connectionId,source:t.source,purpose:t.purpose,resolvedMessageIds:n,providerSnapshot:i})}async exportSelection(t){let n=await ee(t);if(n.purpose!=="export"&&n.purpose!=="scheduled_export")throw new f("selection_purpose_mismatch","This Gmail selection was not prepared for export.",409,!1);te(n,t.expectedCount,t.selectionSha256);let i=U({selectionId:n.selectionId,selectionSha256:n.selectionSha256,expectedCount:n.count}),r=await st({ownerId:t.ownerId,selectionId:n.selectionId,fingerprint:i});if(r.replay)return{...r.replay,replay:!0};if(!r.claimed)throw new f("export_in_progress","This Gmail selection export is already running; retry shortly with the same receipt.",409,!0);let o=[];for(let u of n.messageIds)o.push(await this.getCompleteMessage({ownerId:t.ownerId,providerIdentity:t.providerIdentity,connectionId:t.connectionId,messageId:u}));let a=`gexp_${n.selectionSha256.slice(0,32)}`,s={version:rn,selectionId:n.selectionId,selectionSha256:n.selectionSha256,count:o.length},c=[JSON.stringify({type:"manifest",...s}),...o.map(u=>JSON.stringify({type:"message",message:u}))].join(`
|
|
58
|
+
`)+`
|
|
59
|
+
`,d=await this.createJsonlArtifact({ownerId:t.ownerId,exportId:a,filename:`gmail-${n.selectionId}.jsonl`,content:c,stableCreatedAt:n.createdAt,stableKey:i.slice(0,32)}),l={exportId:a,selectionId:n.selectionId,selectionSha256:n.selectionSha256,count:o.length,status:"complete",artifact:d,sampleMessages:o.slice(0,5).map(fn)};return await ct(t.ownerId,n.selectionId,l),l}async bulkManageSelection(t){let n=await ee(t);if(n.purpose!=="mailbox_action")throw new f("selection_purpose_mismatch","This Gmail selection was not prepared for mailbox actions.",409,!1);te(n,t.expectedCount,t.selectionSha256);let i=U({selectionSha256:n.selectionSha256,operation:t.operation}),r=await ne({ownerId:t.ownerId,idempotencyKey:t.idempotencyKey,fingerprint:i});if(r.replay&&r.execution.result)return r.execution.result;if(r.replay)return{actionId:r.execution.actionId,selectionId:n.selectionId,status:"running",changedCount:0,failedCount:0,failedChunks:[],retryable:!0};let o=[],a=0,s=pn(t.operation);if(s.mode==="batch"){s.validateIds.length&&await this.validateLabels(t.providerIdentity??t.ownerId,t.connectionId,s.validateIds);let d=mt(n.messageIds,1e3);for(let l=0;l<d.length;l++){await ie(r.execution.actionId);let u=`batch:${l}`,p=await B(r.execution.actionId,u);if(!p.claimed){p.receipt.status==="complete"?a+=Number(p.receipt.result?.changedCount??d[l].length):o.push({chunk:l,code:p.receipt.status==="failed"?String(p.receipt.result?.code??"provider_error"):"outcome_unknown"});continue}try{await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"POST",path:"/gmail/v1/users/me/messages/batchModify",body:{ids:d[l],addLabelIds:s.addLabelIds,removeLabelIds:s.removeLabelIds},requestId:`${t.idempotencyKey}:${l}`}),a+=d[l].length,await N(r.execution.actionId,u,"complete",{changedCount:d[l].length})}catch(_){let I=oe(_);o.push({chunk:l,code:I}),await N(r.execution.actionId,u,"failed",{code:I})}}}else for(let d=0;d<n.messageIds.length;d++){await ie(r.execution.actionId);let l=`single:${d}`,u=await B(r.execution.actionId,l);if(!u.claimed){u.receipt.status==="complete"?a+=1:o.length<20&&o.push({chunk:d,code:u.receipt.status==="failed"?String(u.receipt.result?.code??"provider_error"):"outcome_unknown"});continue}try{await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"POST",path:`/gmail/v1/users/me/messages/${encodeURIComponent(n.messageIds[d])}/${s.path}`,body:{},requestId:`${t.idempotencyKey}:${d}`}),a+=1,await N(r.execution.actionId,l,"complete",{changedCount:1})}catch(p){let _=oe(p);o.length<20&&o.push({chunk:d,code:_}),await N(r.execution.actionId,l,"failed",{code:_})}}let c={actionId:r.execution.actionId,selectionId:n.selectionId,status:o.length?"partial":"complete",changedCount:a,failedCount:n.count-a,failedChunks:o.slice(0,20)};return await F(r.execution.actionId,o.length?"partial":"complete",c),c}async permanentlyDeleteSelection(t){if(t.confirmPermanentDelete!==!0)throw new f("permanent_delete_confirmation_required","Set confirmPermanentDelete to true after explicit user confirmation.");let n=await ee(t);if(te(n,t.expectedCount,t.selectionSha256),n.purpose!=="mailbox_action")throw new f("selection_purpose_mismatch","This Gmail selection was not prepared for mailbox actions.",409,!1);let i=U({selectionSha256:n.selectionSha256,operation:"permanent_delete"}),r=await ne({ownerId:t.ownerId,idempotencyKey:t.idempotencyKey,fingerprint:i});if(r.replay&&r.execution.result)return r.execution.result;if(r.replay)return{actionId:r.execution.actionId,selectionId:n.selectionId,status:"running",submittedCount:0,failedCount:0,failedChunks:[],retryable:!0,providerGuarantee:"The original permanent-delete attempt is still being finalized; no provider chunk was replayed."};let o=[],a=0,s=mt(n.messageIds,1e3);for(let d=0;d<s.length;d++){await ie(r.execution.actionId);let l=`delete:${d}`,u=await B(r.execution.actionId,l);if(!u.claimed){u.receipt.status==="complete"?a+=Number(u.receipt.result?.submittedCount??s[d].length):o.push({chunk:d,code:u.receipt.status==="failed"?String(u.receipt.result?.code??"provider_error"):"outcome_unknown"});continue}try{await this.providerCall({identity:t.providerIdentity??t.ownerId,connectionId:t.connectionId,method:"POST",path:"/gmail/v1/users/me/messages/batchDelete",body:{ids:s[d]},requestId:`${t.idempotencyKey}:${d}`}),a+=s[d].length,await N(r.execution.actionId,l,"complete",{submittedCount:s[d].length})}catch(p){let _=oe(p);o.push({chunk:d,code:_}),await N(r.execution.actionId,l,"failed",{code:_})}}let c={actionId:r.execution.actionId,selectionId:n.selectionId,status:o.length?"partial":"complete",submittedCount:a,failedCount:n.count-a,failedChunks:o.slice(0,20),providerGuarantee:"Gmail accepts batch deletion but does not report whether every supplied message previously existed."};return await F(r.execution.actionId,o.length?"partial":"complete",c),c}async validateLabels(t,n,i){let r=v(await this.providerCall({identity:t,connectionId:n,method:"GET",path:"/gmail/v1/users/me/labels"})),o=new Set((Array.isArray(r?.labels)?r.labels:[]).map(s=>h(v(s)?.id)).filter(s=>!!s));if(i.filter(s=>!o.has(s)).length)throw new f("gmail_label_not_found","One or more Gmail label IDs were not found.",404,!1)}};function pn(e){if(e.kind==="trash")return{mode:"single",path:"trash"};if(e.kind==="restore")return{mode:"single",path:"untrash"};if(e.kind==="labels"){let n=[...new Set(e.addLabelIds??[])],i=[...new Set(e.removeLabelIds??[])];if(!n.length&&!i.length)throw new f("invalid_request","At least one label must be added or removed.");if(n.some(r=>i.includes(r)))throw new f("invalid_request","The same label cannot be added and removed.");return{mode:"batch",addLabelIds:n,removeLabelIds:i,validateIds:[...n,...i]}}return{mode:"batch",...{mark_read:{addLabelIds:[],removeLabelIds:["UNREAD"]},mark_unread:{addLabelIds:["UNREAD"],removeLabelIds:[]},archive:{addLabelIds:[],removeLabelIds:["INBOX"]},move_to_inbox:{addLabelIds:["INBOX"],removeLabelIds:[]}}[e.kind],validateIds:[]}}function mt(e,t){let n=[];for(let i=0;i<e.length;i+=t)n.push(e.slice(i,i+t));return n}function oe(e){return e&&typeof e=="object"&&typeof e.code=="string"?String(e.code):"provider_error"}function fn(e){return{messageId:e.messageId,threadId:e.threadId,internalDate:e.internalDate,from:e.from,to:e.to,subject:e.subject,snippet:e.snippet,labels:e.labels,attachmentCount:e.attachments.length}}function _t(e,t){if(!e)return null;if(h(e.partId)===t)return h(v(e.body)?.data);for(let n of Array.isArray(e.parts)?e.parts:[]){let i=_t(v(n),t);if(i!==null)return i}return null}function gn(e,t){if(e.subarray(0,5).toString("ascii")==="%PDF-")return"application/pdf";if(e.subarray(0,4).equals(Buffer.from([80,75,3,4])))return"application/zip";if(e.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])))return"image/png";if(e.subarray(0,3).equals(Buffer.from([255,216,255])))return"image/jpeg";if(t.startsWith("text/"))try{return new TextDecoder("utf-8",{fatal:!0}).decode(e),t}catch{return"application/octet-stream"}if(t==="application/json")try{return JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(e)),t}catch{return"application/octet-stream"}return"application/octet-stream"}export{_n as a,Tt as b,Et as c,x as d,he as e,we as f,Tn as g,w as h,Q as i,ze as j,Gn as k,Dn as l,Un as m,qn as n,Ln as o,Kn as p,tt as q,$n as r,jn as s,S as t,U as u,ee as v,te as w,rn as x,Qn as y,H as z,an as A,f as B,z as C,lt as D,ut as E};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{g as _,i as c}from"./chunk-63T4W2LX.js";var g={kernel:"browserRuntime"},a=/error|message/i,w=/(?:spending|billing|organization|account).{0,80}(?:cap|limit|blocked|disabled)|(?:quota|capacity).{0,40}(?:reached|exceeded)|https?:\/\/\S*(?:dashboard|onkernel)/i,E=/\b(?:ENOENT|ENOTDIR|EACCES|EPERM|EISDIR|EMFILE|ENFILE)\b|\b(?:mkdir|open|stat|lstat|readFile|writeFile)\s+['"]?(?:\/|[A-Za-z]:\\)|(?:^|[\s'"])(?:\/Users|\/home|\/tmp|\/var|\/private|\/opt|\/srv|\/root)\//i,k=new Set(["kernel_session_id","browser_session_id","kernelSessionId","browserSessionId","sessionId","kernel_delete_started","session_cleanup_started","kernelDeleteStarted","sessionCleanupStarted","kernel_delete_succeeded","session_cleanup_succeeded","kernelDeleteSucceeded","sessionCleanupSucceeded","kernel_delete_error","session_cleanup_error","kernelDeleteError","sessionCleanupError","kernelProxyId","proxyId","requestedProxyIdSuffix","retrievedProxyIdSuffix","provider","providerName","service","serviceName","vendor","vendorName","organization","organizationId","accountId","browser_provider","provider_session_id","provider_session_observed_at","provider_lookup_status","provider_status","provider_error_code","provider_error_message","provider_reason_source","provider_duration_ms","provider_bandwidth_bytes","provider_captcha","provider_checked_at","provider_detail","provider_detail_json","provider_disconnect_observed","provider_disconnect_message","browserProvider","providerSessionId","providerLookupStatus","providerStatus","providerErrorCode","providerErrorMessage","providerReasonSource","providerDurationMs","providerBandwidthBytes","providerCaptcha","providerCheckedAt","providerDetail","providerDisconnectObserved","providerDisconnectMessage"]),S=new Set(["hosted_url","hostedUrl","live_view_url","liveViewUrl","cdp_ws_url","cdpWsUrl","browser_live_view_url"]),f=/\b(?:wss?|https?):\/\/[^\s"'<>]*\bonkernel\.com[^\s"'<>]*/gi;function b(e){return e.replace(f,"[browser-service]")}var R=new Set(["bright_data_browser_api","kernel","local"]),m=new Set(["pending","complete","not_found","unavailable_credentials","temporary_error","invalid_payload","not_applicable"]),h=new Set(["active","running","complete","completed","failed","closed","stopped","terminated","timed_out"]),I=new Set(["provider_session_api","client_runtime","extractor","unknown"]),y=new Set(["browser_disconnected","worker_disconnect","job_killed","cdp_cmd_timeout","network_inactivity_timeout","session_timeout","client_timeout","navigate_domains_limit","cdp_error","browser_session_interrupted","provider_detail_pending","provider_lookup_unavailable","provider_reported_no_error","provider_session_not_found","provider_invalid_json","provider_invalid_payload","provider_lookup_timeout","provider_lookup_network_error","unknown"]),T=new Set(["browser_provider","provider_session_id","provider_lookup_status","provider_status","provider_error_code","provider_error_message","provider_reason_source","provider_duration_ms","provider_bandwidth_bytes","provider_captcha","provider_checked_at","provider_detail","provider_detail_json","provider_disconnect_observed","provider_disconnect_message"]),P=512,A=320;function t(e,r){return typeof e=="string"&&r.has(e)?e:null}function O(e){return typeof e!="string"?null:y.has(e)||/^provider_http_(?:429|5\d\d)$/.test(e)?e:null}function D(e){return typeof e!="string"||e.length<1||e.length>P||/^(?:authorization|bearer|password|secret|token|api[_-]?key|account)/i.test(e)?null:/^[A-Za-z0-9._:-]+$/.test(e)&&!e.includes("://")?e:null}function p(e){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=0?e:null}function l(e){if(typeof e!="string"||e.length>40)return null;let r=Date.parse(e);return Number.isFinite(r)&&new Date(r).toISOString()===e?e:null}function u(e){if(typeof e!="string")return null;let r=e.replace(/[\u0000-\u001f\u007f]+/g," ").replace(/\s+/g," ").trim();if(!r||r.startsWith("{")||r.startsWith("["))return null;let o=r.replace(/\b(?:wss?|https?):\/\/\S+/gi,"[redacted endpoint]").replace(/\b(?:authorization|proxy-authorization)\s*:\s*(?:Bearer\s+)?\S+/gi,"[redacted credential]").replace(/\bBearer\s+\S+/gi,"[redacted credential]").replace(/\b(?:api[_-]?key|password|secret|token|account[_-]?id)\s*[=:]\s*[^\s,;]+/gi,"[redacted credential]").replace(/\b(?:account|organization)\s+(?:id\s+)?[A-Za-z0-9_-]{4,}/gi,"[redacted account]");return b(o).slice(0,A)}function v(e){return typeof e=="boolean"?e:null}function N(e){return{browser_provider:t(e.browser_provider,R),provider_session_id:D(e.provider_session_id),provider_session_observed_at:l(e.provider_session_observed_at),provider_lookup_status:t(e.provider_lookup_status,m),provider_status:t(e.provider_status,h),provider_error_code:O(e.provider_error_code),provider_error_message:u(e.provider_error_message),provider_reason_source:t(e.provider_reason_source,I),provider_duration_ms:p(e.provider_duration_ms),provider_bandwidth_bytes:p(e.provider_bandwidth_bytes),provider_captcha:v(e.provider_captcha),provider_checked_at:l(e.provider_checked_at),provider_disconnect_observed:v(e.provider_disconnect_observed),provider_disconnect_message:u(e.provider_disconnect_message)}}function i(e,r=""){if(typeof e=="string"){let o=b(e);return a.test(r)&&(w.test(e)||E.test(e))?o=_("service_unavailable"):a.test(r)&&(o=c(o)),o}if(Array.isArray(e))return e.map(o=>i(o,r));if(e!==null&&typeof e=="object"){let o={};for(let[n,d]of Object.entries(e)){if(k.has(n))continue;let s=g[n]??n;if(S.has(n)){o[s]=null;continue}o[s]=i(d,n)}return o}return e}function L(e){return e.map(r=>{if(r===null||typeof r!="object"||Array.isArray(r))return i(r);let o=r,n=i(o);return Object.keys(o).some(s=>T.has(s))?{...n,...N(o)}:n})}function C(e){let r=e?.diagnostics;return r?.debug?{...e,diagnostics:{...r,debug:i(r.debug)}}:e}export{i as a,L as b,C as c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isIP as I}from"net";import{lookup as T}from"dns/promises";import p from"ipaddr.js";function P(n){return n.startsWith("[")&&n.endsWith("]")?n.slice(1,-1):n}function b(n){let t=P(n);if(!I(t))return!1;try{let e=p.parse(t),s=o=>[["192.0.0.0",24],["192.0.2.0",24],["198.18.0.0",15],["198.51.100.0",24],["203.0.113.0",24]].some(([m,u])=>o.match(p.parse(m),u));if(e instanceof p.IPv6&&e.isIPv4MappedAddress()){let o=e.toIPv4Address();return o.range()!=="unicast"||s(o)}return e instanceof p.IPv4&&s(e)?!0:e.range()!=="unicast"}catch{return!0}}async function N(n){let t=P(n.toLowerCase());if(t==="localhost"||t.endsWith(".localhost")||t.endsWith(".local")||b(t))return!0;try{let e=await T(t,{all:!0,verbatim:!0});return e.length===0||e.some(s=>b(s.address))}catch{return!0}}async function S(n,t){let e;try{e=new URL(n.trim())}catch{return{error:`Invalid ${t.field}`}}return(t.requireHttps?["https:"]:["http:","https:"]).includes(e.protocol)?await N(e.hostname)?{error:`${t.field} must resolve to a public internet host`}:{parsed:e}:{error:t.requireHttps?`${t.field} must use https`:`${t.field} must use http or https`}}import{load as C}from"cheerio";var _="script,style,noscript,svg,iframe,canvas,nav,header,footer,aside",k=4096;function d(n){return(n??"").replace(/\s+/g," ").trim()}function L(n){let t=n.replace(/[\x00-\x09\x0b\x0c\x0e-\x1f]/g," ").trim();if(!t)return null;try{return JSON.parse(t)}catch(e){let s=/at position (\d+)/.exec(e instanceof Error?e.message:"")?.[1];if(!s)return null;try{return JSON.parse(t.slice(0,Number(s)))}catch{return null}}}function g(n,t,e={value:2e3}){if(e.value--<=0||n==null)return;if(Array.isArray(n)){for(let l of n)g(l,t,e);return}if(typeof n!="object")return;let s=n,o=s["@type"];if(typeof o=="string"&&o&&t.add(o),Array.isArray(o))for(let l of o)typeof l=="string"&&l&&t.add(l);Array.isArray(s["@graph"])&&g(s["@graph"],t,e)}function H(n){let t=n("main").first();if(t.length)return t;let e=n("article").first();if(e.length)return e;let s=n("body").first();return s.length?s:n.root()}function w(n,t){let e=Number(n.attr(t)??0);return Number.isFinite(e)&&e>0?e:null}function W(n){let t=C(n),e={};t("meta").each((f,i)=>{let r=t(i),a=d(r.attr("name")??r.attr("property")).toLowerCase(),c=d(r.attr("content"));a&&c&&(e[a]=c)});let s=[];t("h1,h2,h3,h4,h5,h6").each((f,i)=>{let r=t(i),a=d(r.text());a&&s.push({level:Number(i.tagName.slice(1)),text:a})});let o=[],l=new Set;t('script[type="application/ld+json"]').each((f,i)=>{let r=L(t(i).text());r!=null&&(Array.isArray(r)?o.push(...r):o.push(r),g(r,l))});let m=new Set;t("[itemtype]").each((f,i)=>{let r=t(i).attr("itemtype")??"";for(let a of r.split(/\s+/))try{let c=new URL(a);if(c.hostname==="schema.org"||c.hostname==="www.schema.org"){let h=c.pathname.replace(/^\/+/,"");h&&m.add(h)}}catch{}});let u=H(t).clone();u.find(_).remove(),u.find("[href],[src],[srcset],[data-src],[data-srcset]").each((f,i)=>{let r=t(i);for(let a of["href","src","srcset","data-src","data-srcset"]){let c=r.attr(a);c&&c.length>k&&r.removeAttr(a)}}),u.find("img").each((f,i)=>{let r=t(i),a=r.attr("src");if(!a||a.startsWith("data:")){let c=r.attr("data-src")??r.attr("data-lazy-src")??r.attr("data-original");c&&r.attr("src",c)}});let A=u.html()??"",v=d(u.text()),y=[];t("a[href]").each((f,i)=>{let r=t(i),a=d(r.attr("href"));a&&y.push({href:a,text:d(r.text()),rel:d(r.attr("rel")).toLowerCase()||null})});let x=[];return t("img").each((f,i)=>{let r=t(i),a=Object.fromEntries(Object.entries(i.attribs??{}).map(([c,h])=>[c.toLowerCase(),h]));x.push({src:r.attr("src")??r.attr("data-src")??r.attr("data-lazy-src")??r.attr("data-original")??null,srcset:r.attr("srcset")??r.attr("data-srcset")??null,alt:r.attr("alt")??null,width:w(r,"width"),height:w(r,"height"),attributes:a})}),{$:t,sourceHtml:n,title:d(t("title").first().text())||null,meta:e,headings:s,schema:o,schemaTypes:[...l],microdataTypes:[...m],canonicalUrl:d(t('link[rel~="canonical"]').first().attr("href"))||null,mainHtml:A,mainText:v,bodyClass:t("body").first().attr("class")??"",links:y,images:x}}export{b as a,S as b,W as c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as B,randomUUID as N}from"crypto";import{mkdir as O,readFile as T,stat as v,writeFile as U}from"fs/promises";import{homedir as k}from"os";import{dirname as S,join as A}from"path";var d="connected-data-exports/",b=10080*60*1e3,R=900*1e3;function p(){return process.env.CONNECTED_DATA_READ_WRITE_TOKEN?.trim()||process.env.CONNECTED_DATA_BLOB_READ_WRITE_TOKEN?.trim()||null}function D(){return process.env.MCP_SCRAPER_OUTPUT_DIR?.trim()||A(k(),"Downloads","mcp-scraper")}function g(){return process.env.VERCEL==="1"||process.env.NODE_ENV==="production"}function x(t){return(t.toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"connected-data-export").slice(0,120)}function C(t){if(!t.startsWith(d))return null;let e=(t.split("/").at(-1)??"").match(/^(\d{13})-/);if(!e)return null;let r=Number(e[1]);return Number.isFinite(r)?r:null}function _(t){return t.startsWith(d)&&t.slice(d.length).split("/")[0]||null}function P(t){let n=C(t);return n===null?null:new Date(n+b)}function I(t,n=Date.now()){let e=C(t);return e===null||e+b<=n}async function h(t,n){let e=p();if(!e)return null;let r=Math.min(Date.now()+R,n.getTime());if(r<=Date.now())return null;let{issueSignedToken:a,presignUrl:i}=await import("@vercel/blob"),s=await a({token:e,pathname:t,operations:["get"],validUntil:r}),{presignedUrl:o}=await i(s,{access:"private",operation:"get",pathname:t,validUntil:r});return{url:o,expiresAt:new Date(r).toISOString()}}async function H(t){return L({...t,contentType:"application/x-ndjson"})}async function L(t){let n=t.stableCreatedAt?Date.parse(t.stableCreatedAt):Number.NaN,e=Number.isFinite(n)?n:Date.now(),r=x(t.filename),a=r.includes(".")?`.${r.split(".").at(-1)}`:".bin",i=t.stableKey?x(t.stableKey):N(),s=`${d}${t.ownerId}/${e}-${x(t.exportId)}-${i}--${r}`,o=(typeof t.content=="string",Buffer.from(t.content)),u=o.byteLength,c=B("sha256").update(o).digest("hex"),l=new Date(e+b),f=p(),m=s;if(f){let{put:w}=await import("@vercel/blob");m=(await w(s,o,{access:"private",token:f,contentType:t.contentType,addRandomSuffix:!t.stableKey,...t.stableKey?{allowOverwrite:!0}:{},cacheControlMaxAge:60,multipart:u>100*1024*1024})).pathname}else{if(g())throw new Error("connected_data_private_blob_not_configured");let w=A(D(),"blobs",s);await O(S(w),{recursive:!0}),await U(w,o)}let y=await h(m,l);return{artifactId:m,filename:r,contentType:t.contentType,bytes:u,sha256:c,createdAt:new Date(e).toISOString(),expiresAt:l.toISOString(),downloadUrl:y?.url??null,downloadUrlExpiresAt:y?.expiresAt??null,readback:{tool:"report_artifact_read",arguments:{artifactId:m,offset:0,maxBytes:2e4},continuation:"Repeat with offset set to the previous result nextOffset until nextOffset is null."}}}async function V(t){if(_(t.artifactId)!==t.ownerId)return null;let n=P(t.artifactId);if(!n||n.getTime()<=Date.now())return null;let e=await h(t.artifactId,n);return e?{downloadUrl:e.url,downloadUrlExpiresAt:e.expiresAt,expiresAt:n.toISOString()}:null}async function E(t,n=Number.POSITIVE_INFINITY){let e=t.getReader(),r=[],a=0;try{for(;;){let{done:i,value:s}=await e.read();if(i)break;if(s){let o=Buffer.from(s);if(a+=o.byteLength,a>n)return await e.cancel("artifact_too_large").catch(()=>{}),null;r.push(o)}}}finally{e.releaseLock()}return Buffer.concat(r)}async function j(t,n,e){if(I(t))return null;let r=p(),a;if(r){let{get:u}=await import("@vercel/blob"),c=await u(t,{access:"private",token:r,useCache:!1});if(!c||c.statusCode!==200)return null;let l=await E(c.stream);if(!l)return null;a=l}else{if(g())return null;try{a=await T(A(D(),"blobs",t))}catch{return null}}let i=a.length,s=Math.max(0,n),o=Math.min(i,s+e);return{text:a.subarray(s,o).toString("utf8"),totalBytes:i,nextOffset:o<i?o:null}}async function q(t){if(_(t.artifactId)!==t.ownerId||I(t.artifactId))return null;let n=p(),e;if(n){let{get:r}=await import("@vercel/blob"),a=await r(t.artifactId,{access:"private",token:n,useCache:!1});if(!a||a.statusCode!==200)return null;let i=await E(a.stream,t.maxBytes??25*1024*1024);if(!i)return null;e=i}else{if(g())return null;try{let r=A(D(),"blobs",t.artifactId);if((await v(r)).size>(t.maxBytes??25*1024*1024))return null;e=await T(r)}catch{return null}}return e.byteLength>(t.maxBytes??25*1024*1024)?null:e}async function z(t={}){let n=t.now??new Date,e=p();if(!e)return{deleted:0,store:g()?"none":"local"};if(!t.force&&!(n.getUTCHours()===3&&n.getUTCMinutes()===17))return{deleted:0,store:"private-vercel-blob",skipped:!0};let r=n.getTime()-b,{list:a,del:i}=await import("@vercel/blob"),s,o=0;for(let u=0;u<20;u++){let c=await a({prefix:d,token:e,limit:1e3,cursor:s}),l=c.blobs.filter(f=>new Date(f.uploadedAt).getTime()<=r);if(l.length>0&&(await i(l.map(f=>f.pathname),{token:e}),o+=l.length),!c.hasMore||!c.cursor)break;s=c.cursor}return{deleted:o,store:"private-vercel-blob"}}export{d as a,_ as b,H as c,L as d,V as e,j as f,q as g,z as h};
|