mcp-scraper 0.89.5 → 0.89.8
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 +65 -15
- package/README.md +5 -5
- package/dist/{analytics-repository-RG7CFK6W.js → analytics-repository-UX6VU22H.js} +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-core.js +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.js +1 -1
- package/dist/bin/paa-harvest.js +1 -1
- package/dist/{chunk-DBDMD7V7.js → chunk-2BS7MMOS.js} +2 -2
- package/dist/{chunk-NGQYSQQA.js → chunk-2GRE4BAO.js} +1 -1
- package/dist/chunk-2TZBO52D.js +1 -0
- package/dist/chunk-4FROKQJN.js +1 -1
- package/dist/chunk-52XUWR3X.js +820 -0
- package/dist/chunk-5B42QVDC.js +19 -0
- package/dist/chunk-7AC66V3T.js +1 -0
- package/dist/{chunk-7JAMFXNL.js → chunk-7BEWBRMT.js} +153 -86
- package/dist/{chunk-4A5F7IUA.js → chunk-AGK756UE.js} +210 -210
- package/dist/chunk-D6BTAT5Y.js +1 -0
- package/dist/{chunk-53HIX3X7.js → chunk-DKQZNSYM.js} +15 -15
- package/dist/{chunk-MZN4U5BL.js → chunk-E4ME7J6G.js} +1 -1
- package/dist/{chunk-A2CZ7WRV.js → chunk-HR2A2WTL.js} +1 -1
- package/dist/{chunk-XLWNEVUZ.js → chunk-JHMI6HEO.js} +3 -3
- package/dist/{chunk-UB5N2ICD.js → chunk-JSNFZPPB.js} +1 -1
- package/dist/{chunk-WYCXAFID.js → chunk-JVU2THSY.js} +1 -1
- package/dist/{chunk-SEHBXTMX.js → chunk-KX72IORC.js} +6 -6
- package/dist/{chunk-RZSJC7FX.js → chunk-LZTDANNZ.js} +1 -1
- package/dist/{chunk-QPWPR5XG.js → chunk-M5QHXNFZ.js} +3 -3
- package/dist/chunk-MM6QBDPC.js +1 -0
- package/dist/{chunk-3UPA3XHF.js → chunk-PHBU6X5B.js} +1 -1
- package/dist/chunk-Q4A2KIPZ.js +41 -0
- package/dist/{chunk-4SQ4RKDX.js → chunk-TI3KH3YW.js} +1 -1
- package/dist/{chunk-JJDYKM5I.js → chunk-VT6SLBOU.js} +1 -1
- package/dist/{chunk-YQZGZBB4.js → chunk-XG6GCEUE.js} +1 -1
- package/dist/chunk-Z3WXA4ZU.js +1 -0
- package/dist/db-UKQ74OVT.js +1 -0
- package/dist/{extract-bundle-RVOBMGU2.js → extract-bundle-DI7OVLT5.js} +5 -5
- package/dist/gmail-service-ASX7YBC3.js +1 -0
- package/dist/index.cjs +47 -47
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +1 -1
- package/dist/{lead-list-enrichment-repository-GKVCX7BM.js → lead-list-enrichment-repository-GPDHJVM3.js} +1 -1
- package/dist/{location-data-repository-WK27TSHZ.js → location-data-repository-MXUNVDHW.js} +1 -1
- package/dist/{server-7TSXB24M.js → server-PQB2EITA.js} +732 -1551
- package/dist/{site-extract-repository-FAHOTQGX.js → site-extract-repository-WADCAIYB.js} +1 -1
- package/dist/stripe-event-worker-ZPNWXX2T.js +1 -0
- package/dist/worker-GTIKQJIN.js +1 -0
- package/package.json +137 -17
- package/THIRD_PARTY_NOTICES.html +0 -203
- package/dist/chunk-2ICI4TIX.js +0 -59
- package/dist/chunk-3GP5CYZX.js +0 -1
- package/dist/chunk-O2QKRYLS.js +0 -1
- package/dist/chunk-SCHTLEMZ.js +0 -1
- package/dist/db-DV4HHCYP.js +0 -1
- package/dist/gmail-service-FJTBCZPH.js +0 -1
- package/dist/worker-ROG7SO3R.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createClient as Be}from"@libsql/client/http";import{createHash as I,randomBytes as P,randomUUID as g,scryptSync as Te,timingSafeEqual as Ge}from"crypto";import{z as p}from"zod";var k="2026-06-26 21:58:03";var dt="Google returned a CAPTCHA. Run with --headless=false to re-warm the browser profile, then retry.",xe="This operation is temporarily unavailable. Please retry later.",ye=["request_aborted","captcha_exhausted","captcha_or_blocked","location_mismatch","proxy_tunnel_failed","proxy_unavailable","harvest_timeout","mcp_request_timeout","mcp_http_error","extraction_failed","concurrency_limit_exceeded","unauthorized","forbidden","invalid_request","rate_limited","upstream_rate_limited","insufficient_balance","service_unavailable","response_lost","vendor_unavailable","page_not_found","page_forbidden","page_rate_limited","page_server_error","page_http_error","bot_check_unresolved","page_too_large","page_unreachable","browser_session_interrupted","site_export_not_found","site_export_format_unavailable","site_export_read_failed","site_export_image_not_found","image_url_invalid","image_url_not_https","image_host_unresolvable","image_host_blocked","image_redirect_invalid","image_source_unavailable","image_too_large","image_redirect_limit","image_base64_invalid","image_source_missing","image_source_ambiguous","image_source_type_invalid","image_artifact_not_found","image_page_too_large","page_image_not_found","page_image_candidates_unusable","image_format_unsupported","image_storage_unconfigured","featured_image_unhostable"],Ie=["request_aborted","captcha","location_mismatch","connection","timeout","extraction","concurrency_limit","unauthorized","forbidden","invalid_request","rate_limit","billing","service_unavailable"];function R(e){return e?JSON.stringify(e):null}function se(e){if(e==null)return null;try{let t=typeof e=="string"?JSON.parse(e):e;if(!t||typeof t!="object"||Array.isArray(t))return null;let r=t;if(typeof r.error_code!="string"||!ne.has(r.error_code))return null;let s=Pe({errorCode:r.error_code,errorType:r.error_type,retryable:r.retryable,retryAfterSeconds:r.retry_after_seconds,chargeStatus:r.charge_status,details:r.details});if(typeof r.message=="string"){let i=ie(r.message).trim().slice(0,1e3);i&&!/https?:\/\//i.test(i)&&(s.message=i)}return s}catch{return null}}var ne=new Set(ye),Ce=new Set(Ie),ke=new Set(["active","limit","operation","upgrade_url","topup_url","upgrade_command","slots_per_pack","pack_price_usd","balance_credits","required_credits","retry_guidance","http_status"]),Ue=12,De=500;function q(e){return typeof e=="string"&&ne.has(e)?e:"service_unavailable"}function ve(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t={};for(let[r,s]of Object.entries(e)){if(Object.keys(t).length>=Ue)break;if(ke.has(r))if(typeof s=="string"){if((r==="upgrade_url"||r==="topup_url")&&!Xe(s))continue;let i=ie(s).slice(0,De);i&&(t[r]=i)}else(typeof s=="number"&&Number.isFinite(s)||typeof s=="boolean"||s===null)&&(t[r]=s)}return Object.keys(t).length>0?t:void 0}function Xe(e){if(e.startsWith("/")&&!e.startsWith("//"))return!0;try{let t=new URL(e);return t.protocol==="https:"&&(t.hostname==="mcpscraper.dev"||t.hostname.endsWith(".mcpscraper.dev"))}catch{return!1}}function Me(e){let t=q(e);switch(t){case"captcha_exhausted":case"captcha_or_blocked":return"captcha";case"proxy_tunnel_failed":case"proxy_unavailable":case"response_lost":return"connection";case"harvest_timeout":case"mcp_request_timeout":return"timeout";case"concurrency_limit_exceeded":return"concurrency_limit";case"rate_limited":case"upstream_rate_limited":return"rate_limit";case"extraction_failed":case"page_not_found":case"page_forbidden":case"page_rate_limited":case"page_server_error":case"page_http_error":case"bot_check_unresolved":case"page_too_large":case"page_unreachable":case"browser_session_interrupted":case"site_export_not_found":case"site_export_format_unavailable":case"site_export_read_failed":case"site_export_image_not_found":return"extraction";case"image_url_invalid":case"image_url_not_https":case"image_host_unresolvable":case"image_host_blocked":case"image_redirect_invalid":case"image_source_unavailable":case"image_too_large":case"image_redirect_limit":case"image_base64_invalid":case"image_source_missing":case"image_source_ambiguous":case"image_source_type_invalid":case"image_artifact_not_found":case"image_page_too_large":case"page_image_not_found":case"page_image_candidates_unusable":case"image_format_unsupported":case"image_storage_unconfigured":case"featured_image_unhostable":return"invalid_request";case"insufficient_balance":return"billing";case"vendor_unavailable":case"mcp_http_error":return"service_unavailable";default:return t}}function Fe(e){switch(q(e)){case"request_aborted":return"The request was cancelled before it completed.";case"captcha_exhausted":case"captcha_or_blocked":return"The target site returned a verification challenge. Heavy traffic can temporarily increase these challenges; retry in a few minutes.";case"location_mismatch":return"The target site returned results for a different location. Please retry.";case"proxy_tunnel_failed":case"proxy_unavailable":return"The web request could not establish a working connection. Please retry later.";case"harvest_timeout":return"The request timed out before it completed. Please retry with a smaller request.";case"mcp_request_timeout":return"The MCP caller stopped waiting before a final response arrived. Durable work may still be running; continue with the returned Task or job handle instead of restarting it.";case"concurrency_limit_exceeded":return"The service is available, but this account has reached its parallel-operation limit. Wait for an active operation to finish or add capacity.";case"unauthorized":return"Authentication is required to perform this operation.";case"forbidden":return"This account does not have permission to perform this operation.";case"invalid_request":return"The request is invalid. Check the supplied inputs and try again.";case"rate_limited":return"This account is sending requests too quickly. Wait briefly and retry.";case"upstream_rate_limited":return"The connected provider is temporarily rate-limiting requests. Wait briefly and retry.";case"mcp_http_error":return"The API returned an unexpected HTTP response.";case"insufficient_balance":return"This account does not have enough Credits for the operation.";case"extraction_failed":return"The target could not be extracted. Please retry later.";case"response_lost":return"The connection was lost before the response arrived. The operation may have already completed and been billed on our side \u2014 check credits_info before retrying blind.";case"vendor_unavailable":return"MCP Scraper's internal browser services require MCP Scraper team attention. Servers or IPs are down until this is fixed \u2014 this is not caused by your request. Please retry in a few minutes.";case"page_not_found":return"The page could not be found. It may have been moved or deleted.";case"page_forbidden":return"The site refused the request.";case"page_rate_limited":return"The site is rate-limiting requests right now. Retrying after a short wait usually works.";case"page_server_error":return"The page's own server returned an error. This is on the target site's side, not something a retry here can fix.";case"page_http_error":return"The page returned an unexpected HTTP response.";case"bot_check_unresolved":return"This site has automated-traffic protection (a bot/CAPTCHA check) that could not be resolved in time. Some sites are simply not extractable this way.";case"page_too_large":return"The page is larger than we can safely process.";case"page_unreachable":return"The page did not respond in time, or the connection could not be completed.";case"browser_session_interrupted":return"The browser session closed before extraction completed. MCP Scraper will retry once with a fresh session; retry the request if this persists.";case"site_export_not_found":return"The site export or requested page was not found, expired, or does not belong to this account.";case"site_export_format_unavailable":return"That representation was not retained for this export page. Read the export manifest and request one of the formats marked available.";case"site_export_read_failed":return"The stored site export could not be read or did not pass its integrity check.";case"site_export_image_not_found":return"The requested site-export image was not found, expired, or does not belong to this account.";case"image_url_invalid":return"The image source is not a valid URL. Use a stable public HTTPS URL or inline image bytes.";case"image_url_not_https":return"Commons image sources must use a public HTTPS URL or inline image bytes.";case"image_host_unresolvable":return"The image host could not be resolved. Use a different stable public URL or inline image bytes.";case"image_host_blocked":return"The image source resolves to a network address Commons cannot fetch safely.";case"image_redirect_invalid":return"The image source redirected to an invalid or unsafe destination.";case"image_source_unavailable":return"The image source could not be fetched. Host a different stable public URL or provide inline image bytes.";case"image_too_large":return"The image exceeds the Commons image size limit.";case"image_redirect_limit":return"The image source exceeded the Commons redirect limit.";case"image_base64_invalid":return"The supplied inline image bytes are invalid.";case"image_source_missing":return"Provide exactly one of a public image or webpage URL, inline image bytes, or an owner-scoped image artifact.";case"image_source_ambiguous":return"Provide only one image source: sourceUrl, imageBase64, or artifactId.";case"image_source_type_invalid":return"Use sourceType only with inline image bytes or an owner-scoped image artifact.";case"image_artifact_not_found":return"The image artifact was not found, expired, or does not belong to this account.";case"image_page_too_large":return"The webpage is too large for bounded Commons image discovery.";case"page_image_not_found":return"The webpage did not expose a usable featured or content image.";case"page_image_candidates_unusable":return"The webpage exposed image candidates, but none returned supported public image bytes.";case"image_format_unsupported":return"Commons accepts JPEG, PNG, GIF, or WebP image bytes.";case"image_storage_unconfigured":return"Commons image storage is temporarily unavailable.";case"featured_image_unhostable":return"The required featured image could not be hosted for Commons publication.";default:return xe}}function Pe(e){let t=q(e.errorCode),r=typeof e.retryAfterSeconds=="number"&&Number.isFinite(e.retryAfterSeconds)?Math.max(1,Math.min(86400,Math.trunc(e.retryAfterSeconds))):void 0,s=e.chargeStatus==="not_charged"||e.chargeStatus==="refund_pending"||e.chargeStatus==="refunded"||e.chargeStatus==="charged"?e.chargeStatus:void 0,i=typeof e.errorType=="string"&&Ce.has(e.errorType)?e.errorType:void 0,a=ve(e.details);return{error_code:t,error_type:i??Me(t),message:Fe(t),retryable:e.retryable===!0,...r?{retry_after_seconds:r}:{},...s?{charge_status:s}:{},...a?{details:a}:{}}}function ie(e){return e.replace((new RegExp("https?:\\/\\/[^\\s]*(?:\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061|on\u006b\u0065\u0072\u006e\u0065\u006c|\u006b\u0065\u0072\u006e\u0065\u006c\\.sh)[^\\s]*", "gi")),"the service").replace(/bright\s*data/gi,"the service").replace((new RegExp("\u0062\u0072\u0069\u0067\u0068\u0074\u0064\u0061\u0074\u0061", "gi")),"the service").replace((new RegExp("\u006b\u0065\u0072\u006e\u0065\u006c\\.sh\\s+sessions?", "gi")),"sessions").replace((new RegExp("\u006b\u0065\u0072\u006e\u0065\u006c\\.sh\\s+session", "gi")),"this session").replace((new RegExp("\u006b\u0065\u0072\u006e\u0065\u006c\\.sh", "gi")),"the service").replace((new RegExp("\u006b\u0065\u0072\u006e\u0065\u006c\\s+sessions?", "gi")),"sessions").replace((new RegExp("\u006b\u0065\u0072\u006e\u0065\u006c\\s+session", "gi")),"this session").replace(/\b(?:sub|cus|sess|proxy)_[A-Za-z0-9_-]+\b/g,"[redacted]").replace((new RegExp("\\b(?:\u004b\u0045\u0052\u004e\u0045\u004c|\u0042\u0052\u0049\u0047\u0048\u0054\u0044\u0041\u0054\u0041|\u0042\u0052\u0049\u0047\u0048\u0054_\u0044\u0041\u0054\u0041)_[A-Z0-9_]*API_KEY\\b", "g")),"BROWSER_SERVICE_API_KEY").replace((new RegExp("\\b\u006b\u0065\u0072\u006e\u0065\u006c\\b", "gi")),"the service").replace(/ +/g," ").trim()}var z=class extends Error{constructor(r){super(`CAPTCHA detected. ${r}`);this.instructions=r}instructions;name="CaptchaError"},Q=class extends Error{constructor(r,s){super(r);this.cause=s}cause;name="ExtractionError"},Z=class extends Error{constructor(r){super(`Google Maps search did not reach a complete result state (${r})`);this.pageState=r}pageState;name="MapsSearchIncompletePageError"},ee=class extends Error{name="RequestAbortedError";constructor(t="Request aborted before harvest completed"){super(t)}},te=class extends Error{name="PaaInteractionInterruptedError"},re=class extends Error{name="LocationMismatchError";constructor(t="Google returned results for a different location than requested"){super(t)}};var f=["oauth_store_metadata","oauth_clients","oauth_client_redirect_uris","oauth_codes","oauth_code_exchanges","oauth_refresh_families","oauth_refresh_tokens","oauth_refresh_rotations","oauth_security_events","oauth_rate_limit_buckets"],O=["oauth_clients_inactivity_idx","oauth_clients_cleanup_idx","oauth_codes_expiry_idx","oauth_codes_client_idx","oauth_code_exchanges_replay_expiry_idx","oauth_refresh_families_lifecycle_idx","oauth_refresh_families_user_status_idx","oauth_refresh_families_client_idx","oauth_refresh_families_cleanup_idx","oauth_refresh_tokens_expiry_idx","oauth_refresh_rotations_replay_expiry_idx","oauth_security_events_retention_idx","oauth_rate_limit_buckets_expiry_idx"],ae={oauth_clients:"oauth_clients_legacy_raw",oauth_codes:"oauth_codes_legacy_raw",oauth_tokens:"oauth_tokens_legacy_raw"},b="strftime('%Y-%m-%dT%H:%M:%fZ','now')";async function h(e,t,r=!1){try{await e.execute(t)}catch(s){let i=s.code;if(!r||i!=="SQL_PARSE_ERROR")throw s}}var He=[`CREATE TABLE IF NOT EXISTS oauth_store_metadata (
|
|
1
|
+
import{createClient as Be}from"@libsql/client/http";import{createHash as U,randomBytes as P,randomUUID as g,scryptSync as pe,timingSafeEqual as Ge}from"crypto";import{z as p}from"zod";var D="2026-06-26 21:58:03";var dt="Google returned a CAPTCHA. Run with --headless=false to re-warm the browser profile, then retry.",xe="This operation is temporarily unavailable. Please retry later.",ye=["request_aborted","captcha_exhausted","captcha_or_blocked","location_mismatch","proxy_tunnel_failed","proxy_unavailable","harvest_timeout","mcp_request_timeout","mcp_http_error","extraction_failed","concurrency_limit_exceeded","unauthorized","forbidden","invalid_request","rate_limited","upstream_rate_limited","insufficient_balance","service_unavailable","response_lost","vendor_unavailable","page_not_found","page_forbidden","page_rate_limited","page_server_error","page_http_error","bot_check_unresolved","page_too_large","page_unreachable","browser_session_interrupted","site_export_not_found","site_export_format_unavailable","site_export_read_failed","site_export_image_not_found","image_url_invalid","image_url_not_https","image_host_unresolvable","image_host_blocked","image_redirect_invalid","image_source_unavailable","image_too_large","image_redirect_limit","image_base64_invalid","image_source_missing","image_source_ambiguous","image_source_type_invalid","image_artifact_not_found","image_page_too_large","page_image_not_found","page_image_candidates_unusable","image_format_unsupported","image_storage_unconfigured","featured_image_unhostable"],Ie=["request_aborted","captcha","location_mismatch","connection","timeout","extraction","concurrency_limit","unauthorized","forbidden","invalid_request","rate_limit","billing","service_unavailable"];function w(e){return e?JSON.stringify(e):null}function ne(e){if(e==null)return null;try{let t=typeof e=="string"?JSON.parse(e):e;if(!t||typeof t!="object"||Array.isArray(t))return null;let r=t;if(typeof r.error_code!="string"||!ie.has(r.error_code))return null;let s=Pe({errorCode:r.error_code,errorType:r.error_type,retryable:r.retryable,retryAfterSeconds:r.retry_after_seconds,chargeStatus:r.charge_status,details:r.details});if(typeof r.message=="string"){let i=ae(r.message).trim().slice(0,1e3);i&&!/https?:\/\//i.test(i)&&(s.message=i)}return s}catch{return null}}var ie=new Set(ye),Ce=new Set(Ie),Ue=new Set(["active","limit","operation","upgrade_url","topup_url","upgrade_command","slots_per_pack","pack_price_usd","balance_credits","required_credits","retry_guidance","http_status"]),De=12,ke=500;function W(e){return typeof e=="string"&&ie.has(e)?e:"service_unavailable"}function ve(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t={};for(let[r,s]of Object.entries(e)){if(Object.keys(t).length>=De)break;if(Ue.has(r))if(typeof s=="string"){if((r==="upgrade_url"||r==="topup_url")&&!Xe(s))continue;let i=ae(s).slice(0,ke);i&&(t[r]=i)}else(typeof s=="number"&&Number.isFinite(s)||typeof s=="boolean"||s===null)&&(t[r]=s)}return Object.keys(t).length>0?t:void 0}function Xe(e){if(e.startsWith("/")&&!e.startsWith("//"))return!0;try{let t=new URL(e);return t.protocol==="https:"&&(t.hostname==="mcpscraper.dev"||t.hostname.endsWith(".mcpscraper.dev"))}catch{return!1}}function Me(e){let t=W(e);switch(t){case"captcha_exhausted":case"captcha_or_blocked":return"captcha";case"proxy_tunnel_failed":case"proxy_unavailable":case"response_lost":return"connection";case"harvest_timeout":case"mcp_request_timeout":return"timeout";case"concurrency_limit_exceeded":return"concurrency_limit";case"rate_limited":case"upstream_rate_limited":return"rate_limit";case"extraction_failed":case"page_not_found":case"page_forbidden":case"page_rate_limited":case"page_server_error":case"page_http_error":case"bot_check_unresolved":case"page_too_large":case"page_unreachable":case"browser_session_interrupted":case"site_export_not_found":case"site_export_format_unavailable":case"site_export_read_failed":case"site_export_image_not_found":return"extraction";case"image_url_invalid":case"image_url_not_https":case"image_host_unresolvable":case"image_host_blocked":case"image_redirect_invalid":case"image_source_unavailable":case"image_too_large":case"image_redirect_limit":case"image_base64_invalid":case"image_source_missing":case"image_source_ambiguous":case"image_source_type_invalid":case"image_artifact_not_found":case"image_page_too_large":case"page_image_not_found":case"page_image_candidates_unusable":case"image_format_unsupported":case"image_storage_unconfigured":case"featured_image_unhostable":return"invalid_request";case"insufficient_balance":return"billing";case"vendor_unavailable":case"mcp_http_error":return"service_unavailable";default:return t}}function Fe(e){switch(W(e)){case"request_aborted":return"The request was cancelled before it completed.";case"captcha_exhausted":case"captcha_or_blocked":return"The target site returned a verification challenge. Heavy traffic can temporarily increase these challenges; retry in a few minutes.";case"location_mismatch":return"The target site returned results for a different location. Please retry.";case"proxy_tunnel_failed":case"proxy_unavailable":return"The web request could not establish a working connection. Please retry later.";case"harvest_timeout":return"The request timed out before it completed. Please retry with a smaller request.";case"mcp_request_timeout":return"The MCP caller stopped waiting before a final response arrived. Durable work may still be running; continue with the returned Task or job handle instead of restarting it.";case"concurrency_limit_exceeded":return"The service is available, but this account has reached its parallel-operation limit. Wait for an active operation to finish or add capacity.";case"unauthorized":return"Authentication is required to perform this operation.";case"forbidden":return"This account does not have permission to perform this operation.";case"invalid_request":return"The request is invalid. Check the supplied inputs and try again.";case"rate_limited":return"This account is sending requests too quickly. Wait briefly and retry.";case"upstream_rate_limited":return"The connected provider is temporarily rate-limiting requests. Wait briefly and retry.";case"mcp_http_error":return"The API returned an unexpected HTTP response.";case"insufficient_balance":return"This account does not have enough Credits for the operation.";case"extraction_failed":return"The target could not be extracted. Please retry later.";case"response_lost":return"The connection was lost before the response arrived. The operation may have already completed and been billed on our side \u2014 check credits_info before retrying blind.";case"vendor_unavailable":return"MCP Scraper's internal browser services require MCP Scraper team attention. Servers or IPs are down until this is fixed \u2014 this is not caused by your request. Please retry in a few minutes.";case"page_not_found":return"The page could not be found. It may have been moved or deleted.";case"page_forbidden":return"The site refused the request.";case"page_rate_limited":return"The site is rate-limiting requests right now. Retrying after a short wait usually works.";case"page_server_error":return"The page's own server returned an error. This is on the target site's side, not something a retry here can fix.";case"page_http_error":return"The page returned an unexpected HTTP response.";case"bot_check_unresolved":return"This site has automated-traffic protection (a bot/CAPTCHA check) that could not be resolved in time. Some sites are simply not extractable this way.";case"page_too_large":return"The page is larger than we can safely process.";case"page_unreachable":return"The page did not respond in time, or the connection could not be completed.";case"browser_session_interrupted":return"The browser session closed before extraction completed. MCP Scraper will retry once with a fresh session; retry the request if this persists.";case"site_export_not_found":return"The site export or requested page was not found, expired, or does not belong to this account.";case"site_export_format_unavailable":return"That representation was not retained for this export page. Read the export manifest and request one of the formats marked available.";case"site_export_read_failed":return"The stored site export could not be read or did not pass its integrity check.";case"site_export_image_not_found":return"The requested site-export image was not found, expired, or does not belong to this account.";case"image_url_invalid":return"The image source is not a valid URL. Use a stable public HTTPS URL or inline image bytes.";case"image_url_not_https":return"Commons image sources must use a public HTTPS URL or inline image bytes.";case"image_host_unresolvable":return"The image host could not be resolved. Use a different stable public URL or inline image bytes.";case"image_host_blocked":return"The image source resolves to a network address Commons cannot fetch safely.";case"image_redirect_invalid":return"The image source redirected to an invalid or unsafe destination.";case"image_source_unavailable":return"The image source could not be fetched. Host a different stable public URL or provide inline image bytes.";case"image_too_large":return"The image exceeds the Commons image size limit.";case"image_redirect_limit":return"The image source exceeded the Commons redirect limit.";case"image_base64_invalid":return"The supplied inline image bytes are invalid.";case"image_source_missing":return"Provide exactly one of a public image or webpage URL, inline image bytes, or an owner-scoped image artifact.";case"image_source_ambiguous":return"Provide only one image source: sourceUrl, imageBase64, or artifactId.";case"image_source_type_invalid":return"Use sourceType only with inline image bytes or an owner-scoped image artifact.";case"image_artifact_not_found":return"The image artifact was not found, expired, or does not belong to this account.";case"image_page_too_large":return"The webpage is too large for bounded Commons image discovery.";case"page_image_not_found":return"The webpage did not expose a usable featured or content image.";case"page_image_candidates_unusable":return"The webpage exposed image candidates, but none returned supported public image bytes.";case"image_format_unsupported":return"Commons accepts JPEG, PNG, GIF, or WebP image bytes.";case"image_storage_unconfigured":return"Commons image storage is temporarily unavailable.";case"featured_image_unhostable":return"The required featured image could not be hosted for Commons publication.";default:return xe}}function Pe(e){let t=W(e.errorCode),r=typeof e.retryAfterSeconds=="number"&&Number.isFinite(e.retryAfterSeconds)?Math.max(1,Math.min(86400,Math.trunc(e.retryAfterSeconds))):void 0,s=e.chargeStatus==="not_charged"||e.chargeStatus==="refund_pending"||e.chargeStatus==="refunded"||e.chargeStatus==="charged"?e.chargeStatus:void 0,i=typeof e.errorType=="string"&&Ce.has(e.errorType)?e.errorType:void 0,a=ve(e.details);return{error_code:t,error_type:i??Me(t),message:Fe(t),retryable:e.retryable===!0,...r?{retry_after_seconds:r}:{},...s?{charge_status:s}:{},...a?{details:a}:{}}}function ae(e){return e.replace(/https?:\/\/[^\s]*(?:brightdata|onkernel|kernel\.sh)[^\s]*/gi,"the service").replace(/bright\s*data/gi,"the service").replace(/brightdata/gi,"the service").replace(/kernel\.sh\s+sessions?/gi,"sessions").replace(/kernel\.sh\s+session/gi,"this session").replace(/kernel\.sh/gi,"the service").replace(/kernel\s+sessions?/gi,"sessions").replace(/kernel\s+session/gi,"this session").replace(/\b(?:sub|cus|sess|proxy)_[A-Za-z0-9_-]+\b/g,"[redacted]").replace(/\b(?:KERNEL|BRIGHTDATA|BRIGHT_DATA)_[A-Z0-9_]*API_KEY\b/g,"BROWSER_SERVICE_API_KEY").replace(/\bkernel\b/gi,"the service").replace(/ +/g," ").trim()}var Q=class extends Error{constructor(r){super(`CAPTCHA detected. ${r}`);this.instructions=r}instructions;name="CaptchaError"},Z=class extends Error{constructor(r,s){super(r);this.cause=s}cause;name="ExtractionError"},ee=class extends Error{constructor(r){super(`Google Maps search did not reach a complete result state (${r})`);this.pageState=r}pageState;name="MapsSearchIncompletePageError"},te=class extends Error{name="RequestAbortedError";constructor(t="Request aborted before harvest completed"){super(t)}},re=class extends Error{name="PaaInteractionInterruptedError"},se=class extends Error{name="LocationMismatchError";constructor(t="Google returned results for a different location than requested"){super(t)}};var O=["oauth_store_metadata","oauth_clients","oauth_client_redirect_uris","oauth_codes","oauth_code_exchanges","oauth_refresh_families","oauth_refresh_tokens","oauth_refresh_rotations","oauth_security_events","oauth_rate_limit_buckets"],h=["oauth_clients_inactivity_idx","oauth_clients_cleanup_idx","oauth_codes_expiry_idx","oauth_codes_client_idx","oauth_code_exchanges_replay_expiry_idx","oauth_refresh_families_lifecycle_idx","oauth_refresh_families_user_status_idx","oauth_refresh_families_client_idx","oauth_refresh_families_cleanup_idx","oauth_refresh_tokens_expiry_idx","oauth_refresh_rotations_replay_expiry_idx","oauth_security_events_retention_idx","oauth_rate_limit_buckets_expiry_idx"],oe={oauth_clients:"oauth_clients_legacy_raw",oauth_codes:"oauth_codes_legacy_raw",oauth_tokens:"oauth_tokens_legacy_raw"},b="strftime('%Y-%m-%dT%H:%M:%fZ','now')";async function x(e,t,r=!1){try{await e.execute(t)}catch(s){let i=s.code;if(!r||i!=="SQL_PARSE_ERROR")throw s}}var He=[`CREATE TABLE IF NOT EXISTS oauth_store_metadata (
|
|
2
2
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
3
3
|
store_id TEXT NOT NULL UNIQUE,
|
|
4
4
|
schema_version INTEGER NOT NULL CHECK (schema_version > 0),
|
|
@@ -97,9 +97,9 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
97
97
|
reason_code TEXT NOT NULL,
|
|
98
98
|
occurred_at TEXT NOT NULL DEFAULT (${b}),
|
|
99
99
|
retain_until TEXT NOT NULL
|
|
100
|
-
) STRICT`,"CREATE INDEX IF NOT EXISTS oauth_clients_inactivity_idx ON oauth_clients(status, last_used_at, client_id)","CREATE INDEX IF NOT EXISTS oauth_codes_expiry_idx ON oauth_codes(expires_at, code_digest)","CREATE INDEX IF NOT EXISTS oauth_code_exchanges_replay_expiry_idx ON oauth_code_exchanges(replay_expires_at, code_digest)","CREATE INDEX IF NOT EXISTS oauth_refresh_families_lifecycle_idx ON oauth_refresh_families(status, expires_at, family_id)","CREATE INDEX IF NOT EXISTS oauth_refresh_families_user_status_idx ON oauth_refresh_families(user_id, status)","CREATE INDEX IF NOT EXISTS oauth_refresh_tokens_expiry_idx ON oauth_refresh_tokens(expires_at, family_id, generation)","CREATE INDEX IF NOT EXISTS oauth_refresh_rotations_replay_expiry_idx ON oauth_refresh_rotations(replay_expires_at, family_id, predecessor_generation)","CREATE INDEX IF NOT EXISTS oauth_security_events_retention_idx ON oauth_security_events(retain_until, event_id)"],
|
|
100
|
+
) STRICT`,"CREATE INDEX IF NOT EXISTS oauth_clients_inactivity_idx ON oauth_clients(status, last_used_at, client_id)","CREATE INDEX IF NOT EXISTS oauth_codes_expiry_idx ON oauth_codes(expires_at, code_digest)","CREATE INDEX IF NOT EXISTS oauth_code_exchanges_replay_expiry_idx ON oauth_code_exchanges(replay_expires_at, code_digest)","CREATE INDEX IF NOT EXISTS oauth_refresh_families_lifecycle_idx ON oauth_refresh_families(status, expires_at, family_id)","CREATE INDEX IF NOT EXISTS oauth_refresh_families_user_status_idx ON oauth_refresh_families(user_id, status)","CREATE INDEX IF NOT EXISTS oauth_refresh_tokens_expiry_idx ON oauth_refresh_tokens(expires_at, family_id, generation)","CREATE INDEX IF NOT EXISTS oauth_refresh_rotations_replay_expiry_idx ON oauth_refresh_rotations(replay_expires_at, family_id, predecessor_generation)","CREATE INDEX IF NOT EXISTS oauth_security_events_retention_idx ON oauth_security_events(retain_until, event_id)"],ue=["CREATE INDEX IF NOT EXISTS oauth_clients_cleanup_idx ON oauth_clients(COALESCE(last_used_at,created_at), client_id)","CREATE INDEX IF NOT EXISTS oauth_codes_client_idx ON oauth_codes(client_id, code_digest)","CREATE INDEX IF NOT EXISTS oauth_refresh_families_client_idx ON oauth_refresh_families(client_id, family_id)",`CREATE INDEX IF NOT EXISTS oauth_refresh_families_cleanup_idx
|
|
101
101
|
ON oauth_refresh_families(COALESCE(compromised_at,revoked_at,expires_at), family_id)
|
|
102
|
-
WHERE status!='active'`],
|
|
102
|
+
WHERE status!='active'`],q=[`CREATE TABLE IF NOT EXISTS oauth_rate_limit_buckets (
|
|
103
103
|
scope TEXT NOT NULL CHECK (length(scope) BETWEEN 1 AND 80),
|
|
104
104
|
key_digest BLOB NOT NULL CHECK (typeof(key_digest) = 'blob' AND length(key_digest) = 32),
|
|
105
105
|
window_start INTEGER NOT NULL CHECK (window_start >= 0),
|
|
@@ -109,7 +109,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
109
109
|
updated_at TEXT NOT NULL DEFAULT (${b}),
|
|
110
110
|
PRIMARY KEY (scope, key_digest, window_start, window_seconds)
|
|
111
111
|
) STRICT`,`CREATE INDEX IF NOT EXISTS oauth_rate_limit_buckets_expiry_idx
|
|
112
|
-
ON oauth_rate_limit_buckets(expires_at, scope, key_digest, window_start, window_seconds)`],U=[...He,...oe,...W];async function qe(e){if(await h(e,"PRAGMA foreign_keys = ON"),await h(e,"PRAGMA busy_timeout = 5000",!0),(await e.execute("SELECT name FROM pragma_table_info('oauth_codes')")).rows.some(u=>String(u.name)==="code"))throw new Error("Legacy raw OAuth tables require the explicit maintenance-mode coexistence migration");let s=(await e.execute("SELECT 1 present FROM sqlite_master WHERE type='table' AND name='oauth_store_metadata'")).rows.length>0?await e.execute("SELECT schema_version FROM oauth_store_metadata WHERE id=1"):void 0,i=s?.rows[0]?.schema_version==null?void 0:Number(s.rows[0].schema_version);if(i!==void 0&&(!Number.isSafeInteger(i)||i<1||i>3))throw new Error("OAuth store schema version cannot be migrated by this runtime");let a=i===void 0?U:i===1?[...oe,...W]:i===2?W:[];for(let u of a)await e.execute(u);if(i!==void 0&&i<3&&(await e.execute({sql:`UPDATE oauth_store_metadata SET schema_version=?,updated_at=${b} WHERE id=1 AND schema_version=?`,args:[3,i]})).rowsAffected!==1)throw new Error("OAuth store schema version changed during migration");await h(e,"PRAGMA optimize",!0)}async function ue(e){await h(e,"PRAGMA foreign_keys = ON"),await h(e,"PRAGMA busy_timeout = 5000",!0);let t=await e.execute("SELECT name FROM pragma_table_info('oauth_codes')");if(!t.rows.some(a=>String(a.name)==="code")){let a=t.rows.some(u=>String(u.name)==="code_digest");return await qe(e),a?"current":"created"}if((await e.execute({sql:"SELECT name FROM sqlite_master WHERE type='table' AND name IN (?,?,?)",args:Object.values(ae)})).rows.length>0)throw new Error("Legacy OAuth archive names already exist; refusing ambiguous migration");let i=await e.transaction("write");try{for(let[a,u]of Object.entries(ae))(await i.execute({sql:"SELECT 1 present FROM sqlite_master WHERE type='table' AND name=?",args:[a]})).rows.length>0&&await i.execute({sql:`ALTER TABLE ${a} RENAME TO ${u}`,args:[]});for(let a of U)await i.execute({sql:a,args:[]});await i.commit()}finally{i.close()}return"archived_legacy"}var We={oauth_store_metadata:["id","store_id","schema_version","authority_epoch","authority_state","updated_at"],oauth_clients:["client_id","client_name","client_type","token_endpoint_auth_method","status","created_at","last_used_at","expires_at"],oauth_client_redirect_uris:["client_id","redirect_uri","redirect_kind"],oauth_codes:["code_digest","lookup_key_id","client_id","redirect_uri","code_challenge","challenge_method","user_id","scope","resource","issued_at","expires_at"],oauth_code_exchanges:["code_digest","request_fingerprint","client_id","family_id","grant_scope","grant_resource","scope","resource","sealed_refresh","sealed_nonce","sealed_tag","replay_key_id","completed_at","replay_expires_at"],oauth_refresh_families:["family_id","user_id","client_id","issuer","scope","resource","status","current_generation","created_at","expires_at","revoked_at","compromised_at"],oauth_refresh_tokens:["family_id","generation","token_digest","lookup_key_id","token_prefix","predecessor_generation","issued_at","expires_at","used_at","revoked_at"],oauth_refresh_rotations:["family_id","predecessor_generation","request_fingerprint","successor_generation","sealed_successor","sealed_nonce","sealed_tag","replay_key_id","rotated_at","replay_expires_at"],oauth_security_events:["event_id","family_id","event_type","reason_code","occurred_at","retain_until"],oauth_rate_limit_buckets:["scope","key_digest","window_start","window_seconds","count","expires_at","updated_at"]},je={oauth_clients_inactivity_idx:["status","last_used_at","client_id"],oauth_clients_cleanup_idx:[null,"client_id"],oauth_codes_expiry_idx:["expires_at","code_digest"],oauth_codes_client_idx:["client_id","code_digest"],oauth_code_exchanges_replay_expiry_idx:["replay_expires_at","code_digest"],oauth_refresh_families_lifecycle_idx:["status","expires_at","family_id"],oauth_refresh_families_user_status_idx:["user_id","status"],oauth_refresh_families_client_idx:["client_id","family_id"],oauth_refresh_families_cleanup_idx:[null,"family_id"],oauth_refresh_tokens_expiry_idx:["expires_at","family_id","generation"],oauth_refresh_rotations_replay_expiry_idx:["replay_expires_at","family_id","predecessor_generation"],oauth_security_events_retention_idx:["retain_until","event_id"],oauth_rate_limit_buckets_expiry_idx:["expires_at","scope","key_digest","window_start","window_seconds"]};async function ce(e){let t=await e.execute({sql:`SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (${f.map(()=>"?").join(",")})`,args:[...f]}),r=await e.execute({sql:`SELECT name FROM sqlite_master WHERE type = 'index' AND name IN (${O.map(()=>"?").join(",")})`,args:[...O]}),s=new Set(t.rows.map(o=>String(o.name))),i=new Set(r.rows.map(o=>String(o.name))),a=await e.execute("PRAGMA foreign_keys"),u=[],c=o=>o.replace(/\bIF\s+NOT\s+EXISTS\b/gi,"").replace(/\s+/g," ").trim().toLowerCase();for(let o of f){if(!s.has(o))continue;let d=(await e.execute(`PRAGMA table_info('${o}')`)).rows.map(N=>String(N.name));JSON.stringify(d)!==JSON.stringify(We[o])&&u.push(`${o}:columns`);let E=await e.execute({sql:"SELECT sql FROM sqlite_master WHERE type='table' AND name=?",args:[o]}),l=String(E.rows[0]?.sql??""),m=U.find(N=>c(N).startsWith(`create table ${o} `));(!m||c(l)!==c(m))&&u.push(`${o}:definition`)}for(let o of O){if(!i.has(o))continue;let d=(await e.execute(`PRAGMA index_info('${o}')`)).rows.map(N=>N.name==null?null:String(N.name));JSON.stringify(d)!==JSON.stringify(je[o])&&u.push(`${o}:columns`);let E=await e.execute({sql:"SELECT sql FROM sqlite_master WHERE type='index' AND name=?",args:[o]}),l=String(E.rows[0]?.sql??""),m=U.find(N=>c(N).startsWith(`create index ${o} `));(!m||c(l)!==c(m))&&u.push(`${o}:definition`)}return{ok:f.every(o=>s.has(o))&&O.every(o=>i.has(o))&&Number(a.rows[0]?.foreign_keys??0)===1&&u.length===0,missingTables:f.filter(o=>!s.has(o)),missingIndexes:O.filter(o=>!i.has(o)),foreignKeysEnabled:Number(a.rows[0]?.foreign_keys??0)===1,problems:u}}var Ye=process.env.TURSO_DATABASE_URL??"file:./paa-api.db",Je=process.env.TURSO_AUTH_TOKEN,v=null,y="2026-09-15.1",_e="data-2026-07-28-site-extract-counters.1",de=["admin_credit_adjustment_events","admin_credit_adjustments","billing_authorizations","billing_credits","billing_debits","billing_debit_allocations","billing_events","browser_profile_labels","connected_account_billing","concurrency_locks","credit_lot_expirations","credit_lots","credit_lot_repairs","free_credit_refreshes","harvest_attempts","inbox_messages","jobs","kpo_jobs","kpo_phase_log","ledger","oauth_clients","oauth_codes","oauth_tokens","page_snapshots","password_reset_tokens","rate_limits","request_events","scheduled_run_view_links","serp_identities","site_audit_jobs","site_audit_phase_log","site_extract_jobs","site_extract_pages","stripe_events","users","workflow_artifacts","workflow_runs","workflow_schedules","workflow_webhook_deliveries","workshop_registrations"],le=["admin_credit_adjustment_events_reference","admin_credit_adjustments_user_created","billing_authorizations_user_status","billing_credits_user_status","billing_debits_user_status","billing_events_authorization","billing_events_user_created_at","concurrency_locks_active_user","concurrency_locks_operation","concurrency_locks_user_status","credit_lots_user_active","credit_lot_repairs_user_applied","harvest_attempts_job_id","harvest_attempts_provider_lookup","harvest_attempts_user_created_at","inbox_messages_user_sent_at","jobs_created_at_status_user","jobs_status","jobs_user_created_at_status","jobs_user_id","kpo_jobs_status","kpo_jobs_user_id","kpo_phase_log_job_id","ledger_stripe_pi_unique","ledger_user_id","oauth_tokens_identity","page_snapshots_user_checked_at","prt_user_id","request_events_created_at","request_events_user_created_at","scheduled_run_view_links_expiry","scheduled_run_view_links_owner_run","serp_identities_user_name","site_audit_jobs_status","site_audit_jobs_user_id","site_audit_phase_log_job_id","site_extract_jobs_status","site_extract_jobs_idempotency","site_extract_jobs_user_id","site_extract_pages_job_id","workflow_artifacts_run","workflow_runs_idempotency","workflow_runs_schedule","workflow_runs_user_created","workflow_schedules_due","workflow_schedules_user_status","workflow_webhook_deliveries_run","workshop_registrations_event_status"],Ee=["credit_lots_bounds_insert","credit_lots_bounds_update","credit_lots_one_migration_insert","credit_lots_one_migration_update"],$e={credit_lots:["never_expires"],harvest_attempts:["debug_json","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_json","provider_disconnect_observed","provider_disconnect_message"],jobs:["public_error_json"],oauth_tokens:["replaced_by","rotated_at"],site_extract_jobs:["attempted_urls","successful_urls","failed_urls","idempotency_key","request_fingerprint","dispatch_attempts","next_dispatch_at","dispatch_error","settlement_attempts","next_settlement_at","settlement_error","public_error_json"],stripe_events:["attempt_count","claim_token","last_error","status","updated_at"],users:["balance_mc","concurrency_stripe_sub_id","concurrency_pack_quantity","extra_concurrency_slots","key_active","memory_identity","memory_key","memory_plan","memory_provisioned","memory_subscription_id","password_hash","stripe_customer_id","subscription_concurrency","subscription_id","subscription_tier"],workshop_registrations:["field_notes_email_id","reminder_48h_email_id","reminder_24h_email_id","reminder_1h_email_id"],workflow_artifacts:["content"],workflow_runs:["step_index","step_log_json","step_state_json","total_steps","webhook_url"]};function D(e){return e.map(t=>`'${t.replaceAll("'","''")}'`).join(", ")}async function X(e){let t=[`(SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name IN (${D(de)})) = ${de.length}`,`(SELECT COUNT(*) FROM sqlite_master WHERE type = 'index' AND name IN (${D(le)})) = ${le.length}`,`(SELECT COUNT(*) FROM sqlite_master WHERE type = 'trigger' AND name IN (${D(Ee)})) = ${Ee.length}`,...Object.entries($e).map(([s,i])=>`(SELECT COUNT(*) FROM pragma_table_info('${s}') WHERE name IN (${D(i)})) = ${i.length}`)],r=await e.execute(`SELECT ${t.join(" AND ")} AS ready`);return Number(r.rows[0]?.ready??0)===1}async function Lt(e=n()){let t=!1;try{t=(await e.execute({sql:"SELECT 1 AS applied FROM schema_migrations WHERE version = ? LIMIT 1",args:[y]})).rows.length===1}catch(s){let i=s instanceof Error?s.message.toLowerCase():String(s).toLowerCase();if(!i.includes("no such table")||!i.includes("schema_migrations"))throw s}let r=t?await X(e):!1;return{coreSchemaVersion:y,migrationApplied:t,schemaReady:r}}async function Ke(e){await e.execute(`
|
|
112
|
+
ON oauth_rate_limit_buckets(expires_at, scope, key_digest, window_start, window_seconds)`],k=[...He,...ue,...q];async function We(e){if(await x(e,"PRAGMA foreign_keys = ON"),await x(e,"PRAGMA busy_timeout = 5000",!0),(await e.execute("SELECT name FROM pragma_table_info('oauth_codes')")).rows.some(u=>String(u.name)==="code"))throw new Error("Legacy raw OAuth tables require the explicit maintenance-mode coexistence migration");let s=(await e.execute("SELECT 1 present FROM sqlite_master WHERE type='table' AND name='oauth_store_metadata'")).rows.length>0?await e.execute("SELECT schema_version FROM oauth_store_metadata WHERE id=1"):void 0,i=s?.rows[0]?.schema_version==null?void 0:Number(s.rows[0].schema_version);if(i!==void 0&&(!Number.isSafeInteger(i)||i<1||i>3))throw new Error("OAuth store schema version cannot be migrated by this runtime");let a=i===void 0?k:i===1?[...ue,...q]:i===2?q:[];for(let u of a)await e.execute(u);if(i!==void 0&&i<3&&(await e.execute({sql:`UPDATE oauth_store_metadata SET schema_version=?,updated_at=${b} WHERE id=1 AND schema_version=?`,args:[3,i]})).rowsAffected!==1)throw new Error("OAuth store schema version changed during migration");await x(e,"PRAGMA optimize",!0)}async function ce(e){await x(e,"PRAGMA foreign_keys = ON"),await x(e,"PRAGMA busy_timeout = 5000",!0);let t=await e.execute("SELECT name FROM pragma_table_info('oauth_codes')");if(!t.rows.some(a=>String(a.name)==="code")){let a=t.rows.some(u=>String(u.name)==="code_digest");return await We(e),a?"current":"created"}if((await e.execute({sql:"SELECT name FROM sqlite_master WHERE type='table' AND name IN (?,?,?)",args:Object.values(oe)})).rows.length>0)throw new Error("Legacy OAuth archive names already exist; refusing ambiguous migration");let i=await e.transaction("write");try{for(let[a,u]of Object.entries(oe))(await i.execute({sql:"SELECT 1 present FROM sqlite_master WHERE type='table' AND name=?",args:[a]})).rows.length>0&&await i.execute({sql:`ALTER TABLE ${a} RENAME TO ${u}`,args:[]});for(let a of k)await i.execute({sql:a,args:[]});await i.commit()}finally{i.close()}return"archived_legacy"}var qe={oauth_store_metadata:["id","store_id","schema_version","authority_epoch","authority_state","updated_at"],oauth_clients:["client_id","client_name","client_type","token_endpoint_auth_method","status","created_at","last_used_at","expires_at"],oauth_client_redirect_uris:["client_id","redirect_uri","redirect_kind"],oauth_codes:["code_digest","lookup_key_id","client_id","redirect_uri","code_challenge","challenge_method","user_id","scope","resource","issued_at","expires_at"],oauth_code_exchanges:["code_digest","request_fingerprint","client_id","family_id","grant_scope","grant_resource","scope","resource","sealed_refresh","sealed_nonce","sealed_tag","replay_key_id","completed_at","replay_expires_at"],oauth_refresh_families:["family_id","user_id","client_id","issuer","scope","resource","status","current_generation","created_at","expires_at","revoked_at","compromised_at"],oauth_refresh_tokens:["family_id","generation","token_digest","lookup_key_id","token_prefix","predecessor_generation","issued_at","expires_at","used_at","revoked_at"],oauth_refresh_rotations:["family_id","predecessor_generation","request_fingerprint","successor_generation","sealed_successor","sealed_nonce","sealed_tag","replay_key_id","rotated_at","replay_expires_at"],oauth_security_events:["event_id","family_id","event_type","reason_code","occurred_at","retain_until"],oauth_rate_limit_buckets:["scope","key_digest","window_start","window_seconds","count","expires_at","updated_at"]},je={oauth_clients_inactivity_idx:["status","last_used_at","client_id"],oauth_clients_cleanup_idx:[null,"client_id"],oauth_codes_expiry_idx:["expires_at","code_digest"],oauth_codes_client_idx:["client_id","code_digest"],oauth_code_exchanges_replay_expiry_idx:["replay_expires_at","code_digest"],oauth_refresh_families_lifecycle_idx:["status","expires_at","family_id"],oauth_refresh_families_user_status_idx:["user_id","status"],oauth_refresh_families_client_idx:["client_id","family_id"],oauth_refresh_families_cleanup_idx:[null,"family_id"],oauth_refresh_tokens_expiry_idx:["expires_at","family_id","generation"],oauth_refresh_rotations_replay_expiry_idx:["replay_expires_at","family_id","predecessor_generation"],oauth_security_events_retention_idx:["retain_until","event_id"],oauth_rate_limit_buckets_expiry_idx:["expires_at","scope","key_digest","window_start","window_seconds"]};async function _e(e){let t=await e.execute({sql:`SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (${O.map(()=>"?").join(",")})`,args:[...O]}),r=await e.execute({sql:`SELECT name FROM sqlite_master WHERE type = 'index' AND name IN (${h.map(()=>"?").join(",")})`,args:[...h]}),s=new Set(t.rows.map(o=>String(o.name))),i=new Set(r.rows.map(o=>String(o.name))),a=await e.execute("PRAGMA foreign_keys"),u=[],c=o=>o.replace(/\bIF\s+NOT\s+EXISTS\b/gi,"").replace(/\s+/g," ").trim().toLowerCase();for(let o of O){if(!s.has(o))continue;let d=(await e.execute(`PRAGMA table_info('${o}')`)).rows.map(N=>String(N.name));JSON.stringify(d)!==JSON.stringify(qe[o])&&u.push(`${o}:columns`);let E=await e.execute({sql:"SELECT sql FROM sqlite_master WHERE type='table' AND name=?",args:[o]}),l=String(E.rows[0]?.sql??""),m=k.find(N=>c(N).startsWith(`create table ${o} `));(!m||c(l)!==c(m))&&u.push(`${o}:definition`)}for(let o of h){if(!i.has(o))continue;let d=(await e.execute(`PRAGMA index_info('${o}')`)).rows.map(N=>N.name==null?null:String(N.name));JSON.stringify(d)!==JSON.stringify(je[o])&&u.push(`${o}:columns`);let E=await e.execute({sql:"SELECT sql FROM sqlite_master WHERE type='index' AND name=?",args:[o]}),l=String(E.rows[0]?.sql??""),m=k.find(N=>c(N).startsWith(`create index ${o} `));(!m||c(l)!==c(m))&&u.push(`${o}:definition`)}return{ok:O.every(o=>s.has(o))&&h.every(o=>i.has(o))&&Number(a.rows[0]?.foreign_keys??0)===1&&u.length===0,missingTables:O.filter(o=>!s.has(o)),missingIndexes:h.filter(o=>!i.has(o)),foreignKeysEnabled:Number(a.rows[0]?.foreign_keys??0)===1,problems:u}}var Ye=process.env.TURSO_DATABASE_URL??"file:./paa-api.db",$e=process.env.TURSO_AUTH_TOKEN,X=null,I="2026-09-18.1",de="data-2026-07-28-site-extract-counters.1",le=["admin_credit_adjustment_events","admin_credit_adjustments","billing_authorizations","billing_credits","billing_debits","billing_debit_allocations","billing_events","browser_profile_labels","connected_account_billing","concurrency_locks","credit_lot_expirations","credit_lots","credit_lot_repairs","free_credit_refreshes","harvest_attempts","inbox_messages","jobs","kpo_jobs","kpo_phase_log","ledger","oauth_clients","oauth_codes","oauth_tokens","page_snapshots","password_reset_tokens","rate_limits","request_events","scheduled_run_view_links","serp_identities","site_audit_jobs","site_audit_phase_log","site_extract_jobs","site_extract_pages","stripe_events","users","workflow_artifacts","workflow_runs","workflow_schedules","workflow_webhook_deliveries","workshop_registrations"],Ee=["admin_credit_adjustment_events_reference","admin_credit_adjustments_user_created","billing_authorizations_user_status","billing_credits_user_status","billing_debits_user_status","billing_events_authorization","billing_events_user_created_at","concurrency_locks_active_user","concurrency_locks_operation","concurrency_locks_user_status","credit_lots_user_active","credit_lot_repairs_user_applied","harvest_attempts_job_id","harvest_attempts_provider_lookup","harvest_attempts_user_created_at","inbox_messages_user_sent_at","jobs_created_at_status_user","jobs_status","jobs_user_created_at_status","jobs_user_id","kpo_jobs_status","kpo_jobs_user_id","kpo_phase_log_job_id","ledger_stripe_pi_unique","ledger_user_id","oauth_tokens_identity","page_snapshots_user_checked_at","prt_user_id","request_events_created_at","request_events_user_created_at","scheduled_run_view_links_expiry","scheduled_run_view_links_owner_run","stripe_events_due","serp_identities_user_name","site_audit_jobs_status","site_audit_jobs_user_id","site_audit_phase_log_job_id","site_extract_jobs_status","site_extract_jobs_idempotency","site_extract_jobs_user_id","site_extract_pages_job_id","workflow_artifacts_run","workflow_runs_idempotency","workflow_runs_schedule","workflow_runs_user_created","workflow_schedules_due","workflow_schedules_user_status","workflow_webhook_deliveries_run","workshop_registrations_event_status"],Te=["credit_lots_bounds_insert","credit_lots_bounds_update","credit_lots_one_migration_insert","credit_lots_one_migration_update"],Je={credit_lots:["never_expires"],harvest_attempts:["debug_json","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_json","provider_disconnect_observed","provider_disconnect_message"],jobs:["public_error_json"],oauth_tokens:["replaced_by","rotated_at"],site_extract_jobs:["attempted_urls","successful_urls","failed_urls","idempotency_key","request_fingerprint","dispatch_attempts","next_dispatch_at","dispatch_error","settlement_attempts","next_settlement_at","settlement_error","public_error_json"],stripe_events:["attempt_count","claim_token","claimed_at","completed_at","event_type","last_error","last_error_code","next_attempt_at","received_at","status","stripe_created_at","updated_at"],users:["balance_mc","concurrency_stripe_sub_id","concurrency_pack_quantity","extra_concurrency_slots","key_active","memory_identity","memory_key","memory_plan","memory_provisioned","memory_subscription_id","password_hash","stripe_customer_id","subscription_concurrency","subscription_id","subscription_tier"],workshop_registrations:["field_notes_email_id","reminder_48h_email_id","reminder_24h_email_id","reminder_1h_email_id"],workflow_artifacts:["content"],workflow_runs:["step_index","step_log_json","step_state_json","total_steps","webhook_url"]};function v(e){return e.map(t=>`'${t.replaceAll("'","''")}'`).join(", ")}async function M(e){let t=[`(SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name IN (${v(le)})) = ${le.length}`,`(SELECT COUNT(*) FROM sqlite_master WHERE type = 'index' AND name IN (${v(Ee)})) = ${Ee.length}`,`(SELECT COUNT(*) FROM sqlite_master WHERE type = 'trigger' AND name IN (${v(Te)})) = ${Te.length}`,...Object.entries(Je).map(([s,i])=>`(SELECT COUNT(*) FROM pragma_table_info('${s}') WHERE name IN (${v(i)})) = ${i.length}`)],r=await e.execute(`SELECT ${t.join(" AND ")} AS ready`);return Number(r.rows[0]?.ready??0)===1}async function Lt(e=n()){let t=!1;try{t=(await e.execute({sql:"SELECT 1 AS applied FROM schema_migrations WHERE version = ? LIMIT 1",args:[I]})).rows.length===1}catch(s){let i=s instanceof Error?s.message.toLowerCase():String(s).toLowerCase();if(!i.includes("no such table")||!i.includes("schema_migrations"))throw s}let r=t?await M(e):!1;return{coreSchemaVersion:I,migrationApplied:t,schemaReady:r}}async function Ke(e){await e.execute(`
|
|
113
113
|
UPDATE site_extract_jobs SET
|
|
114
114
|
attempted_urls = done_urls,
|
|
115
115
|
successful_urls = (
|
|
@@ -146,12 +146,12 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
146
146
|
AND attempted_urls = 0
|
|
147
147
|
AND successful_urls = 0
|
|
148
148
|
AND failed_urls = 0
|
|
149
|
-
`)}async function j(e){(await e.execute({sql:"SELECT 1 AS applied FROM schema_migrations WHERE version = ? LIMIT 1",args:[
|
|
149
|
+
`)}async function j(e){(await e.execute({sql:"SELECT 1 AS applied FROM schema_migrations WHERE version = ? LIMIT 1",args:[de]})).rows.length>0||(await Ke(e),await e.execute({sql:"INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)",args:[de]}))}function n(){return X||(X=Be({url:Ye,authToken:$e})),X}function St(e){X=e}async function Rt(e=n()){if(process.env.OAUTH_MAINTENANCE_MODE!=="true")throw new Error("Secured main OAuth schema migration requires OAUTH_MAINTENANCE_MODE=true");await ce(e)}async function At(e=n()){return _e(e)}async function wt(e={}){let t=n(),r;try{r=await t.execute({sql:"SELECT 1 AS applied FROM schema_migrations WHERE version = ? LIMIT 1",args:[I]})}catch(s){let i=s instanceof Error?s.message.toLowerCase():String(s).toLowerCase();if(!i.includes("no such table")||!i.includes("schema_migrations"))throw s;await t.execute(`
|
|
150
150
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
151
151
|
version TEXT PRIMARY KEY,
|
|
152
152
|
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
153
153
|
)
|
|
154
|
-
`),r={rows:[]}}if(r.rows.length>0){if(!e.verifyCurrentSchema)return;if(await
|
|
154
|
+
`),r={rows:[]}}if(r.rows.length>0){if(!e.verifyCurrentSchema)return;if(await M(t)){e.runDataRepairs&&await j(t);return}}if(await M(t)){await j(t),await t.execute({sql:"INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)",args:[I]});return}await t.execute(`
|
|
155
155
|
CREATE TABLE IF NOT EXISTS users (
|
|
156
156
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
157
157
|
email TEXT UNIQUE NOT NULL,
|
|
@@ -188,14 +188,14 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
188
188
|
max_questions INTEGER NOT NULL,
|
|
189
189
|
status TEXT NOT NULL,
|
|
190
190
|
outcome TEXT,
|
|
191
|
-
|
|
191
|
+
kernel_session_id TEXT,
|
|
192
192
|
question_count INTEGER,
|
|
193
193
|
duration_ms INTEGER,
|
|
194
194
|
error TEXT,
|
|
195
195
|
will_retry INTEGER,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
kernel_delete_started INTEGER NOT NULL DEFAULT 0,
|
|
197
|
+
kernel_delete_succeeded INTEGER,
|
|
198
|
+
kernel_delete_error TEXT,
|
|
199
199
|
browser_close_succeeded INTEGER,
|
|
200
200
|
browser_close_error TEXT,
|
|
201
201
|
debug_json TEXT,
|
|
@@ -645,19 +645,37 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
645
645
|
status TEXT NOT NULL DEFAULT 'processed',
|
|
646
646
|
attempt_count INTEGER NOT NULL DEFAULT 1,
|
|
647
647
|
claim_token TEXT,
|
|
648
|
+
event_type TEXT,
|
|
649
|
+
stripe_created_at INTEGER,
|
|
650
|
+
received_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
651
|
+
claimed_at TEXT,
|
|
652
|
+
next_attempt_at TEXT,
|
|
653
|
+
completed_at TEXT,
|
|
648
654
|
last_error TEXT,
|
|
655
|
+
last_error_code TEXT,
|
|
649
656
|
processed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
650
657
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
651
658
|
)
|
|
652
|
-
`);for(let s of["status TEXT NOT NULL DEFAULT 'processed'","attempt_count INTEGER NOT NULL DEFAULT 1","claim_token TEXT","last_error TEXT","updated_at TEXT"])try{await t.execute(`ALTER TABLE stripe_events ADD COLUMN ${s}`)}catch{}await t.execute(`
|
|
659
|
+
`);for(let s of["status TEXT NOT NULL DEFAULT 'processed'","attempt_count INTEGER NOT NULL DEFAULT 1","claim_token TEXT","event_type TEXT","stripe_created_at INTEGER","received_at TEXT","claimed_at TEXT","next_attempt_at TEXT","completed_at TEXT","last_error TEXT","last_error_code TEXT","updated_at TEXT"])try{await t.execute(`ALTER TABLE stripe_events ADD COLUMN ${s}`)}catch{}await t.execute(`
|
|
653
660
|
UPDATE stripe_events
|
|
654
661
|
SET updated_at = COALESCE(updated_at, processed_at),
|
|
655
|
-
|
|
656
|
-
|
|
662
|
+
received_at = COALESCE(received_at, processed_at, updated_at, datetime('now')),
|
|
663
|
+
claimed_at = CASE WHEN status = 'processing' THEN COALESCE(claimed_at, updated_at, processed_at) ELSE claimed_at END,
|
|
664
|
+
next_attempt_at = CASE WHEN status = 'failed' THEN COALESCE(next_attempt_at, datetime('now')) ELSE next_attempt_at END,
|
|
665
|
+
completed_at = CASE WHEN status = 'processed' THEN COALESCE(completed_at, processed_at, updated_at) ELSE completed_at END,
|
|
666
|
+
status = CASE WHEN status = 'failed' THEN 'retryable' ELSE COALESCE(status, 'processed') END,
|
|
667
|
+
attempt_count = CASE WHEN status = 'pending' THEN MAX(0, COALESCE(attempt_count, 0)) ELSE MAX(1, COALESCE(attempt_count, 1)) END
|
|
657
668
|
WHERE updated_at IS NULL
|
|
669
|
+
OR received_at IS NULL
|
|
658
670
|
OR status IS NULL
|
|
671
|
+
OR status = 'failed'
|
|
672
|
+
OR (status = 'processing' AND claimed_at IS NULL)
|
|
673
|
+
OR (status = 'processed' AND completed_at IS NULL)
|
|
659
674
|
OR attempt_count IS NULL
|
|
660
|
-
OR attempt_count <
|
|
675
|
+
OR attempt_count < 0
|
|
676
|
+
`),await t.execute(`
|
|
677
|
+
CREATE INDEX IF NOT EXISTS stripe_events_due
|
|
678
|
+
ON stripe_events(status, next_attempt_at, claimed_at, received_at)
|
|
661
679
|
`),await t.execute(`
|
|
662
680
|
CREATE TABLE IF NOT EXISTS oauth_clients (
|
|
663
681
|
client_id TEXT PRIMARY KEY,
|
|
@@ -749,8 +767,8 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
749
767
|
id TEXT PRIMARY KEY,
|
|
750
768
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
751
769
|
name TEXT NOT NULL,
|
|
752
|
-
|
|
753
|
-
|
|
770
|
+
kernel_profile_name TEXT NOT NULL,
|
|
771
|
+
kernel_proxy_id TEXT NOT NULL,
|
|
754
772
|
proxy_type TEXT NOT NULL DEFAULT 'isp',
|
|
755
773
|
country TEXT NOT NULL DEFAULT 'US',
|
|
756
774
|
status TEXT NOT NULL DEFAULT 'ready',
|
|
@@ -762,45 +780,62 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
762
780
|
`),await t.execute(`
|
|
763
781
|
CREATE UNIQUE INDEX IF NOT EXISTS serp_identities_user_name
|
|
764
782
|
ON serp_identities(user_id, name)
|
|
765
|
-
`),!await
|
|
766
|
-
(event_id, status, attempt_count,
|
|
767
|
-
VALUES (?, '
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
783
|
+
`),!await M(t))throw new Error("core schema migration finished without all required tables, indexes, and columns");await j(t),await t.execute({sql:"INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)",args:[I]})}async function ft(e,t,r){await n().execute({sql:"INSERT INTO oauth_clients (client_id, redirect_uris, name) VALUES (?, ?, ?)",args:[e,JSON.stringify(t),r]})}async function Ot(e){let r=(await n().execute({sql:"SELECT * FROM oauth_clients WHERE client_id = ?",args:[e]})).rows[0];if(!r)return;let s=[];try{let i=JSON.parse(String(r.redirect_uris));Array.isArray(i)&&(s=i.filter(a=>typeof a=="string"))}catch{s=[]}return{client_id:String(r.client_id),redirect_uris:s,name:r.name!=null?String(r.name):null,created_at:String(r.created_at)}}async function ht(e){await n().execute({sql:"INSERT INTO oauth_codes (code, client_id, redirect_uri, code_challenge, identity, scope, resource, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",args:[e.code,e.client_id,e.redirect_uri,e.code_challenge,e.identity,e.scope,e.resource,e.expires_at]})}async function xt(e){let t=n(),s=(await t.execute({sql:"SELECT * FROM oauth_codes WHERE code = ?",args:[e]})).rows[0];if(await t.execute({sql:"DELETE FROM oauth_codes WHERE code = ?",args:[e]}),!!s)return{code:String(s.code),client_id:String(s.client_id),redirect_uri:String(s.redirect_uri),code_challenge:String(s.code_challenge),identity:String(s.identity),scope:String(s.scope),resource:s.resource!=null?String(s.resource):null,expires_at:String(s.expires_at)}}async function Ve(e){await n().execute({sql:"INSERT INTO oauth_tokens (refresh_token, client_id, identity, scope, resource, expires_at, revoked) VALUES (?, ?, ?, ?, ?, ?, 0)",args:[e.refresh_token,e.client_id,e.identity,e.scope,e.resource,e.expires_at]})}async function yt(e){let r=(await n().execute({sql:"SELECT * FROM oauth_tokens WHERE refresh_token = ?",args:[e]})).rows[0];if(r)return{refresh_token:String(r.refresh_token),client_id:String(r.client_id),identity:String(r.identity),scope:String(r.scope),resource:r.resource!=null?String(r.resource):null,expires_at:String(r.expires_at),revoked:Number(r.revoked??0),replaced_by:r.replaced_by!=null?String(r.replaced_by):null,rotated_at:r.rotated_at!=null?String(r.rotated_at):null}}async function It(e){await n().execute({sql:"UPDATE oauth_tokens SET revoked = 1 WHERE refresh_token = ?",args:[e]})}async function Ct(e,t){await Ve(t),await n().execute({sql:"UPDATE oauth_tokens SET revoked = 1, replaced_by = ?, rotated_at = ? WHERE refresh_token = ?",args:[t.refresh_token,new Date().toISOString(),e]})}async function Ut(e,t,r){return(await n().execute({sql:`INSERT OR IGNORE INTO stripe_events
|
|
784
|
+
(event_id, event_type, stripe_created_at, status, attempt_count, received_at, next_attempt_at, processed_at, updated_at)
|
|
785
|
+
VALUES (?, ?, ?, 'pending', 0, datetime('now'), datetime('now'), datetime('now'), datetime('now'))`,args:[e,t,r]})).rowsAffected===1?"queued":"duplicate"}async function Dt(e=50,t=300){let r=Math.max(1,Math.min(500,Math.trunc(e))),s=await n().execute({sql:`SELECT event_id
|
|
786
|
+
FROM stripe_events
|
|
787
|
+
WHERE (status IN ('pending', 'retryable') AND COALESCE(next_attempt_at, received_at) <= datetime('now'))
|
|
788
|
+
OR (status = 'processing' AND claimed_at <= datetime('now', '-' || ? || ' seconds'))
|
|
789
|
+
ORDER BY COALESCE(next_attempt_at, received_at), received_at
|
|
790
|
+
LIMIT ?`,args:[t,r]}),i=[];for(let a of s.rows){let u=String(a.event_id),c=g();if((await n().execute({sql:`UPDATE stripe_events
|
|
791
|
+
SET status = 'processing', attempt_count = attempt_count + 1,
|
|
792
|
+
claim_token = ?, claimed_at = datetime('now'), last_error = NULL,
|
|
793
|
+
last_error_code = NULL, updated_at = datetime('now')
|
|
794
|
+
WHERE event_id = ?
|
|
795
|
+
AND ((status IN ('pending', 'retryable') AND COALESCE(next_attempt_at, received_at) <= datetime('now'))
|
|
796
|
+
OR (status = 'processing' AND claimed_at <= datetime('now', '-' || ? || ' seconds')))`,args:[c,u,t]})).rowsAffected!==1)continue;let _=await n().execute({sql:"SELECT event_type, attempt_count FROM stripe_events WHERE event_id = ? LIMIT 1",args:[u]});i.push({eventId:u,eventType:_.rows[0]?.event_type!=null?String(_.rows[0].event_type):null,attemptCount:Number(_.rows[0]?.attempt_count??1),token:c})}return i}async function kt(e,t){return(await n().execute({sql:`UPDATE stripe_events
|
|
779
797
|
SET status = 'processed',
|
|
780
798
|
claim_token = NULL,
|
|
799
|
+
claimed_at = NULL,
|
|
800
|
+
next_attempt_at = NULL,
|
|
801
|
+
completed_at = datetime('now'),
|
|
781
802
|
last_error = NULL,
|
|
782
803
|
processed_at = datetime('now'),
|
|
783
804
|
updated_at = datetime('now')
|
|
784
|
-
WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[e,t]})).rowsAffected===1}async function
|
|
785
|
-
SET status = '
|
|
805
|
+
WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[e,t]})).rowsAffected===1}async function vt(e,t,r,s,i){return(await n().execute({sql:`UPDATE stripe_events
|
|
806
|
+
SET status = 'retryable',
|
|
786
807
|
claim_token = NULL,
|
|
808
|
+
claimed_at = NULL,
|
|
787
809
|
last_error = ?,
|
|
810
|
+
last_error_code = ?,
|
|
811
|
+
next_attempt_at = datetime('now', '+' || ? || ' seconds'),
|
|
788
812
|
updated_at = datetime('now')
|
|
789
|
-
WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[r.slice(0,500),
|
|
813
|
+
WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[r.slice(0,500),s.slice(0,100),Math.max(0,Math.trunc(i)),e,t]})).rowsAffected===1}async function Xt(e,t,r,s){return(await n().execute({sql:`UPDATE stripe_events
|
|
814
|
+
SET status = 'dead_letter', claim_token = NULL, claimed_at = NULL,
|
|
815
|
+
last_error = ?, last_error_code = ?, next_attempt_at = NULL, updated_at = datetime('now')
|
|
816
|
+
WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[r.slice(0,500),s.slice(0,100),e,t]})).rowsAffected===1}async function Mt(){let t=(await n().execute(`
|
|
817
|
+
SELECT
|
|
818
|
+
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending,
|
|
819
|
+
SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END) AS processing,
|
|
820
|
+
SUM(CASE WHEN status = 'retryable' THEN 1 ELSE 0 END) AS retryable,
|
|
821
|
+
SUM(CASE WHEN status = 'dead_letter' THEN 1 ELSE 0 END) AS dead_letter,
|
|
822
|
+
MIN(CASE WHEN status IN ('pending', 'retryable') THEN COALESCE(next_attempt_at, received_at) END) AS oldest_due_at
|
|
823
|
+
FROM stripe_events
|
|
824
|
+
`)).rows[0];return{pending:Number(t?.pending??0),processing:Number(t?.processing??0),retryable:Number(t?.retryable??0),dead_letter:Number(t?.dead_letter??0),oldest_due_at:t?.oldest_due_at!=null?String(t.oldest_due_at):null}}async function Ft(e){return(await n().execute({sql:"SELECT 1 FROM stripe_events WHERE event_id = ? AND status = 'processed' LIMIT 1",args:[e]})).rows.length>0}function me(){return"sk_"+P(24).toString("hex")}function ge(e){let t=P(16).toString("hex"),r=pe(e,t,64);return`${t}:${r.toString("hex")}`}function Pt(e,t){let[r,s]=t.split(":"),i=Buffer.from(s,"hex"),a=pe(e,r,64);return Ge(i,a)}function L(e){return{id:Number(e.id),email:String(e.email),name:e.name!=null?String(e.name):null,api_key:String(e.api_key),key_active:Number(e.key_active??1),password_hash:e.password_hash!=null?String(e.password_hash):null,created_at:String(e.created_at),active:Number(e.active),stripe_customer_id:e.stripe_customer_id!=null?String(e.stripe_customer_id):null,balance_mc:Number(e.balance_mc??0),extra_concurrency_slots:Number(e.extra_concurrency_slots??0),concurrency_stripe_sub_id:e.concurrency_stripe_sub_id!=null?String(e.concurrency_stripe_sub_id):null,concurrency_pack_quantity:Number(e.concurrency_pack_quantity??0),subscription_concurrency:Number(e.subscription_concurrency??0),subscription_tier:e.subscription_tier!=null?String(e.subscription_tier):null,subscription_id:e.subscription_id!=null?String(e.subscription_id):null,memory_plan:e.memory_plan!=null?String(e.memory_plan):"free",memory_subscription_id:e.memory_subscription_id!=null?String(e.memory_subscription_id):null,memory_provisioned:Number(e.memory_provisioned??0)}}async function Ht(e){let t=await n().execute({sql:"SELECT * FROM users WHERE email = ? AND active = 1",args:[e]});return t.rows[0]?L(t.rows[0]):void 0}async function Wt(e){let t=await n().execute({sql:"SELECT * FROM users WHERE api_key = ? AND active = 1 AND key_active = 1",args:[e]});return t.rows[0]?L(t.rows[0]):void 0}async function qt(e){let t=await n().execute({sql:"SELECT * FROM users WHERE id = ? AND active = 1",args:[e]});return t.rows[0]?L(t.rows[0]):void 0}async function jt(e){let r=(await n().execute({sql:"SELECT memory_key, memory_identity FROM users WHERE id = ?",args:[e]})).rows[0];return{memory_key:r?.memory_key!=null?String(r.memory_key):null,memory_identity:r?.memory_identity!=null?String(r.memory_identity):null}}async function Bt(e,t,r){await n().execute({sql:"UPDATE users SET memory_key = ?, memory_identity = ? WHERE id = ?",args:[t,r,e]})}async function Gt(e,t){await n().execute({sql:"UPDATE users SET password_hash = ? WHERE id = ?",args:[ge(t),e]})}async function Yt(e){let t=n(),[r,s,i,a,u]=await Promise.all([t.execute({sql:"SELECT COUNT(*) as n FROM jobs WHERE user_id = ?",args:[e]}),t.execute({sql:"SELECT COUNT(*) as n FROM jobs WHERE user_id = ? AND status = 'done'",args:[e]}),t.execute({sql:"SELECT COUNT(*) as n FROM jobs WHERE user_id = ? AND status = 'failed'",args:[e]}),t.execute({sql:"SELECT COALESCE(SUM(json_extract(result, '$.totalQuestions')), 0) as n FROM jobs WHERE user_id = ? AND status = 'done'",args:[e]}),t.execute({sql:"SELECT MAX(created_at) as t FROM jobs WHERE user_id = ?",args:[e]})]);return{total:Number(r.rows[0]?.n??0),done:Number(s.rows[0]?.n??0),failed:Number(i.rows[0]?.n??0),totalQuestions:Number(a.rows[0]?.n??0),lastUsed:u.rows[0]?.t!=null?String(u.rows[0].t):null}}async function $t(e,t,r,s){let i=n(),a=me(),u=r??P(6).toString("hex"),c=ge(u);return{id:(await i.execute({sql:"INSERT INTO users (email, name, api_key, password_hash, stripe_customer_id) VALUES (?, ?, ?, ?, ?)",args:[e,t??null,a,c,s??null]})).lastInsertRowid,email:e,name:t,api_key:a,password:u}}async function Jt(e,t,r,s){let i=Math.floor(Date.now()/1e3),a=Math.floor(i/s)*s,u=U("sha256").update(t).digest("hex"),o=await n().execute({sql:`
|
|
790
825
|
INSERT INTO rate_limits (scope, key_hash, window_start, count)
|
|
791
826
|
VALUES (?, ?, ?, 1)
|
|
792
827
|
ON CONFLICT(scope, key_hash, window_start)
|
|
793
828
|
DO UPDATE SET count = count + 1, updated_at = datetime('now')
|
|
794
829
|
RETURNING count
|
|
795
|
-
`,args:[e,u,a]}),_=Number(o.rows[0]?.count);if(!Number.isSafeInteger(_)||_<1)throw new Error("Rate-limit bucket mutation did not return a valid count");return{allowed:_<=r,count:_,remaining:Math.max(0,r-_),resetSeconds:Math.max(1,a+s-i)}}async function
|
|
830
|
+
`,args:[e,u,a]}),_=Number(o.rows[0]?.count);if(!Number.isSafeInteger(_)||_<1)throw new Error("Rate-limit bucket mutation did not return a valid count");return{allowed:_<=r,count:_,remaining:Math.max(0,r-_),resetSeconds:Math.max(1,a+s-i)}}async function Kt(e){let t=P(32).toString("hex"),r=U("sha256").update(t).digest("hex"),s=new Date(Date.now()+3600*1e3).toISOString();return await n().execute({sql:"INSERT INTO password_reset_tokens (token, user_id, expires_at) VALUES (?, ?, ?)",args:[r,e,s]}),t}async function Vt(e){let t=n(),r=U("sha256").update(e).digest("hex"),i=(await t.execute({sql:"SELECT user_id, expires_at, used FROM password_reset_tokens WHERE token = ?",args:[r]})).rows[0];return!i||Number(i.used)||new Date(String(i.expires_at))<new Date?null:(await t.execute({sql:"UPDATE password_reset_tokens SET used = 1 WHERE token = ?",args:[r]}),Number(i.user_id))}async function zt(e){let t=me();return await n().execute({sql:"UPDATE users SET api_key = ?, key_active = 1 WHERE id = ?",args:[t,e]}),t}async function Qt(e){await n().execute({sql:"UPDATE users SET key_active = 0 WHERE id = ?",args:[e]})}async function Zt(){return(await n().execute("SELECT id, email, name, created_at, active FROM users ORDER BY created_at DESC")).rows.map(t=>L({...t,api_key:"",key_active:1}))}async function er(e){await n().execute({sql:"UPDATE users SET active = 0 WHERE id = ?",args:[e]})}function S(e){return{id:String(e.id),user_id:Number(e.user_id),status:String(e.status),query:String(e.query),options:String(e.options),callback_url:e.callback_url!=null?String(e.callback_url):null,result:e.result!=null?String(e.result):null,error:e.error!=null?String(e.error):null,public_error_json:e.public_error_json!=null?String(e.public_error_json):null,created_at:String(e.created_at),started_at:e.started_at!=null?String(e.started_at):null,completed_at:e.completed_at!=null?String(e.completed_at):null}}function y(e){return e==null?null:Number(e)===1}function F(e){if(e==null)return null;try{return JSON.parse(String(e))}catch{return null}}function Ne(e){return{id:String(e.id),job_id:String(e.job_id),user_id:Number(e.user_id),attempt_number:Number(e.attempt_number),max_attempts:Number(e.max_attempts),query:String(e.query),location:e.location!=null?String(e.location):null,max_questions:Number(e.max_questions),status:String(e.status),outcome:e.outcome!=null?String(e.outcome):null,kernel_session_id:e.kernel_session_id!=null?String(e.kernel_session_id):null,question_count:e.question_count!=null?Number(e.question_count):null,duration_ms:e.duration_ms!=null?Number(e.duration_ms):null,error:e.error!=null?String(e.error):null,will_retry:y(e.will_retry),kernel_delete_started:Number(e.kernel_delete_started??0)===1,kernel_delete_succeeded:y(e.kernel_delete_succeeded),kernel_delete_error:e.kernel_delete_error!=null?String(e.kernel_delete_error):null,browser_close_succeeded:y(e.browser_close_succeeded),browser_close_error:e.browser_close_error!=null?String(e.browser_close_error):null,browser_provider:e.browser_provider!=null?String(e.browser_provider):null,provider_session_id:e.provider_session_id!=null?String(e.provider_session_id):null,provider_session_observed_at:e.provider_session_observed_at!=null?String(e.provider_session_observed_at):null,provider_lookup_status:e.provider_lookup_status!=null?String(e.provider_lookup_status):null,provider_status:e.provider_status!=null?String(e.provider_status):null,provider_error_code:e.provider_error_code!=null?String(e.provider_error_code):null,provider_error_message:e.provider_error_message!=null?String(e.provider_error_message):null,provider_reason_source:e.provider_reason_source!=null?String(e.provider_reason_source):null,provider_duration_ms:e.provider_duration_ms!=null?Number(e.provider_duration_ms):null,provider_bandwidth_bytes:e.provider_bandwidth_bytes!=null?Number(e.provider_bandwidth_bytes):null,provider_captcha:y(e.provider_captcha),provider_checked_at:e.provider_checked_at!=null?String(e.provider_checked_at):null,provider_detail:F(e.provider_detail_json),provider_disconnect_observed:y(e.provider_disconnect_observed),provider_disconnect_message:e.provider_disconnect_message!=null?String(e.provider_disconnect_message):null,debug:F(e.debug_json),created_at:String(e.created_at),completed_at:e.completed_at!=null?String(e.completed_at):null}}function f(e){let{public_error_json:t,...r}=e;return{...r,options:JSON.parse(e.options),result:e.result?JSON.parse(e.result):null,publicError:ne(t)}}async function tr(e,t,r,s){let i=g();return await ze(i,e,t,r,s),i}async function ze(e,t,r,s,i){if(!/^[a-zA-Z0-9-]{1,100}$/.test(e))throw new Error("job id is invalid");await n().execute({sql:"INSERT INTO jobs (id, user_id, query, options, callback_url) VALUES (?, ?, ?, ?, ?)",args:[e,t,r,JSON.stringify(s),i??null]})}async function rr(e,t,r){let s=g();return await n().execute({sql:"INSERT INTO jobs (id, user_id, query, options, status, started_at) VALUES (?, ?, ?, ?, 'running', datetime('now'))",args:[s,e,t,JSON.stringify(r)]}),s}async function sr(e,t,r,s){let i=await n().execute({sql:`INSERT INTO jobs (id, user_id, query, options, status, started_at)
|
|
796
831
|
VALUES (?, ?, ?, ?, 'running', datetime('now'))
|
|
797
|
-
ON CONFLICT(id) DO NOTHING`,args:[e,t,r,JSON.stringify(s)]}),a=await
|
|
832
|
+
ON CONFLICT(id) DO NOTHING`,args:[e,t,r,JSON.stringify(s)]}),a=await G(e,t);if(!a)throw new Error(`getOrCreateRunningJob: row missing immediately after insert/lookup for ${e}`);return{job:a,created:i.rowsAffected===1}}async function nr(e){await n().execute({sql:`
|
|
798
833
|
INSERT INTO harvest_attempts (
|
|
799
834
|
id, job_id, user_id, attempt_number, max_attempts, query, location, max_questions, status, created_at
|
|
800
835
|
)
|
|
801
836
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'running', ?)
|
|
802
837
|
ON CONFLICT(job_id, attempt_number) DO NOTHING
|
|
803
|
-
`,args:[g(),e.jobId,e.userId,e.attemptNumber,e.maxAttempts,e.query,e.location,e.maxQuestions,e.startedAt]})}async function
|
|
838
|
+
`,args:[g(),e.jobId,e.userId,e.attemptNumber,e.maxAttempts,e.query,e.location,e.maxQuestions,e.startedAt]})}async function ir(e){return(await n().execute({sql:`
|
|
804
839
|
UPDATE harvest_attempts SET
|
|
805
840
|
browser_provider = ?,
|
|
806
841
|
provider_session_id = ?,
|
|
@@ -810,7 +845,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
810
845
|
ELSE 'pending'
|
|
811
846
|
END
|
|
812
847
|
WHERE job_id = ? AND attempt_number = ? AND status = 'running'
|
|
813
|
-
`,args:[e.browserProvider,e.providerSessionId,e.observedAt,e.jobId,e.attemptNumber]})).rowsAffected===1}async function
|
|
848
|
+
`,args:[e.browserProvider,e.providerSessionId,e.observedAt,e.jobId,e.attemptNumber]})).rowsAffected===1}async function ar(e,t,r=new Date().toISOString()){return(await n().execute({sql:`
|
|
814
849
|
UPDATE harvest_attempts SET
|
|
815
850
|
status = 'finished',
|
|
816
851
|
outcome = COALESCE(outcome, 'timeout'),
|
|
@@ -823,18 +858,18 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
823
858
|
provider_reason_source = COALESCE(provider_reason_source, 'client_runtime'),
|
|
824
859
|
completed_at = COALESCE(completed_at, ?)
|
|
825
860
|
WHERE job_id = ? AND status = 'running'
|
|
826
|
-
`,args:[r,t?1:0,r,e]})).rowsAffected}async function
|
|
861
|
+
`,args:[r,t?1:0,r,e]})).rowsAffected}async function or(e){await n().execute({sql:`
|
|
827
862
|
UPDATE harvest_attempts SET
|
|
828
863
|
status = 'finished',
|
|
829
864
|
outcome = ?,
|
|
830
|
-
|
|
865
|
+
kernel_session_id = ?,
|
|
831
866
|
question_count = ?,
|
|
832
867
|
duration_ms = ?,
|
|
833
868
|
error = ?,
|
|
834
869
|
will_retry = ?,
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
870
|
+
kernel_delete_started = ?,
|
|
871
|
+
kernel_delete_succeeded = ?,
|
|
872
|
+
kernel_delete_error = ?,
|
|
838
873
|
browser_close_succeeded = ?,
|
|
839
874
|
browser_close_error = ?,
|
|
840
875
|
browser_provider = COALESCE(browser_provider, ?),
|
|
@@ -866,7 +901,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
866
901
|
debug_json = ?,
|
|
867
902
|
completed_at = ?
|
|
868
903
|
WHERE job_id = ? AND attempt_number = ?
|
|
869
|
-
`,args:[e.outcome,e
|
|
904
|
+
`,args:[e.outcome,e.kernelSessionId,e.questionCount,e.durationMs,e.error,e.willRetry?1:0,e.kernelDeleteStarted?1:0,e.kernelDeleteSucceeded==null?null:e.kernelDeleteSucceeded?1:0,e.kernelDeleteError,e.browserCloseSucceeded==null?null:e.browserCloseSucceeded?1:0,e.browserCloseError,e.browserProvider??null,e.providerSessionId??null,e.providerLookupStatus??null,e.providerStatus??null,e.providerErrorCode??null,e.providerErrorMessage??null,e.providerReasonSource??null,e.providerDurationMs??null,e.providerBandwidthBytes??null,e.providerCaptcha==null?null:e.providerCaptcha?1:0,e.providerCheckedAt??null,e.providerDetail==null?null:be(e.providerDetail),e.providerDisconnectObserved==null?null:e.providerDisconnectObserved?1:0,e.providerDisconnectMessage??null,e.debug==null?null:JSON.stringify(e.debug),e.completedAt,e.jobId,e.attemptNumber]})}function be(e,t=4096){let r=JSON.stringify(e);return r.length<=t?r:JSON.stringify({truncated:!0})}async function ur(e){return(await n().execute({sql:`
|
|
870
905
|
UPDATE harvest_attempts SET
|
|
871
906
|
provider_lookup_status = ?,
|
|
872
907
|
provider_status = ?,
|
|
@@ -881,23 +916,42 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
881
916
|
WHERE id = ?
|
|
882
917
|
AND job_id = ?
|
|
883
918
|
AND user_id = ?
|
|
884
|
-
AND browser_provider = '
|
|
919
|
+
AND browser_provider = 'bright_data_browser_api'
|
|
885
920
|
AND provider_session_id = ?
|
|
886
921
|
AND COALESCE(provider_lookup_status, '') <> 'complete'
|
|
887
|
-
`,args:[e.lookupStatus,e.providerStatus??null,e.errorCode??null,e.errorMessage??null,e.reasonSource??null,e.durationMs??null,e.bandwidthBytes??null,e.captcha==null?null:e.captcha?1:0,e.checkedAt,e.detail==null?null:
|
|
922
|
+
`,args:[e.lookupStatus,e.providerStatus??null,e.errorCode??null,e.errorMessage??null,e.reasonSource??null,e.durationMs??null,e.bandwidthBytes??null,e.captcha==null?null:e.captcha?1:0,e.checkedAt,e.detail==null?null:be(e.detail),e.attemptId,e.jobId,e.userId,e.providerSessionId]})).rowsAffected===1}async function cr(e=25){let t=Math.max(1,Math.min(100,Math.trunc(e)));return(await n().execute({sql:`
|
|
888
923
|
SELECT * FROM harvest_attempts
|
|
889
|
-
WHERE browser_provider = '
|
|
924
|
+
WHERE browser_provider = 'bright_data_browser_api'
|
|
890
925
|
AND provider_session_id IS NOT NULL
|
|
891
926
|
AND provider_lookup_status IN ('pending', 'temporary_error')
|
|
892
927
|
ORDER BY COALESCE(provider_checked_at, created_at) ASC
|
|
893
928
|
LIMIT ?
|
|
894
|
-
`,args:[t]})).rows.map(s=>
|
|
929
|
+
`,args:[t]})).rows.map(s=>Ne(s))}async function _r(e,t){return(t==null?await n().execute({sql:"SELECT * FROM harvest_attempts WHERE job_id = ? ORDER BY attempt_number ASC",args:[e]}):await n().execute({sql:`
|
|
895
930
|
SELECT ha.*
|
|
896
931
|
FROM harvest_attempts ha
|
|
897
932
|
INNER JOIN jobs j ON j.id = ha.job_id
|
|
898
933
|
WHERE ha.job_id = ? AND j.user_id = ?
|
|
899
934
|
ORDER BY ha.attempt_number ASC
|
|
900
|
-
`,args:[e,t]})).rows.map(s=>
|
|
935
|
+
`,args:[e,t]})).rows.map(s=>Ne(s))}async function G(e,t){let r=n(),s=t?await r.execute({sql:"SELECT * FROM jobs WHERE id = ? AND user_id = ?",args:[e,t]}):await r.execute({sql:"SELECT * FROM jobs WHERE id = ?",args:[e]});return s.rows[0]?f(S(s.rows[0])):void 0}async function dr(e,t,r){await n().execute({sql:`UPDATE jobs
|
|
936
|
+
SET status = 'running', started_at = COALESCE(started_at, datetime('now'))
|
|
937
|
+
WHERE id = ? AND status = 'pending'
|
|
938
|
+
AND json_extract(options, '$.executionOwner') = ?
|
|
939
|
+
AND json_extract(options, '$.jobKind') = ?`,args:[e,t,r]});let s=await G(e);if(!(!s||s.options.executionOwner!==t||s.options.jobKind!==r))return s}async function lr(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await n().execute({sql:`SELECT * FROM jobs
|
|
940
|
+
WHERE status = 'pending'
|
|
941
|
+
AND json_extract(options, '$.executionOwner') = 'inngest'
|
|
942
|
+
AND json_extract(options, '$.jobKind') = 'extract_url'
|
|
943
|
+
AND json_extract(options, '$.billingDebitKey') IS NOT NULL
|
|
944
|
+
AND created_at <= datetime('now', '-30 seconds')
|
|
945
|
+
AND datetime(COALESCE(json_extract(options, '$.extractUrlLastDispatchAt'), '1970-01-01')) <= datetime('now', '-30 seconds')
|
|
946
|
+
ORDER BY created_at
|
|
947
|
+
LIMIT ?`,args:[t]})).rows.map(s=>f(S(s)))}async function Er(e,t){return(await n().execute({sql:`UPDATE jobs
|
|
948
|
+
SET options = json_set(options,
|
|
949
|
+
'$.extractUrlDispatchAttempts', COALESCE(json_extract(options, '$.extractUrlDispatchAttempts'), 0) + 1,
|
|
950
|
+
'$.extractUrlLastDispatchAt', ?,
|
|
951
|
+
'$.extractUrlLastDispatchError', ?)
|
|
952
|
+
WHERE id = ? AND status = 'pending'
|
|
953
|
+
AND json_extract(options, '$.executionOwner') = 'inngest'
|
|
954
|
+
AND json_extract(options, '$.jobKind') = 'extract_url'`,args:[new Date().toISOString(),t??null,e]})).rowsAffected===1}async function Tr(e){return(await n().execute({sql:"SELECT * FROM jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50",args:[e]})).rows.map(r=>f(S(r)))}async function pr(e,t){let s=(await n().execute({sql:"SELECT content_hash, content, title, content_bytes, truncated, checked_at FROM page_snapshots WHERE user_id = ? AND url = ?",args:[e,t]})).rows[0];return s?{contentHash:String(s.content_hash),content:String(s.content),title:s.title==null?null:String(s.title),contentBytes:Number(s.content_bytes),truncated:Number(s.truncated)===1,checkedAt:String(s.checked_at)}:null}async function mr(e,t,r){await n().execute({sql:`
|
|
901
955
|
INSERT INTO page_snapshots (user_id, url, content_hash, content, title, content_bytes, truncated, checked_at)
|
|
902
956
|
VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
903
957
|
ON CONFLICT(user_id, url) DO UPDATE SET
|
|
@@ -907,56 +961,56 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
907
961
|
content_bytes = excluded.content_bytes,
|
|
908
962
|
truncated = excluded.truncated,
|
|
909
963
|
checked_at = excluded.checked_at
|
|
910
|
-
`,args:[e,t,r.contentHash,r.content,r.title,r.contentBytes,r.truncated?1:0]})}var Qe=32*1024;function Ze(e){if(e==null)return null;let t=JSON.stringify(e),r=Buffer.byteLength(t,"utf8");return r<=Qe?t:JSON.stringify({truncated:!0,originalBytes:r,sha256:
|
|
964
|
+
`,args:[e,t,r.contentHash,r.content,r.title,r.contentBytes,r.truncated?1:0]})}var Qe=32*1024;function Ze(e){if(e==null)return null;let t=JSON.stringify(e),r=Buffer.byteLength(t,"utf8");return r<=Qe?t:JSON.stringify({truncated:!0,originalBytes:r,sha256:U("sha256").update(t).digest("hex")})}function et(e){let t=e.result!=null?String(e.result):null;return{id:String(e.id),user_id:Number(e.user_id),source:String(e.source),status:String(e.status),query:String(e.query),location:e.location!=null?String(e.location):null,result_count:e.result_count!=null?Number(e.result_count):null,result:t?JSON.parse(t):null,error:e.error!=null?String(e.error):null,created_at:String(e.created_at)}}async function gr(e){let t=g();return await n().execute({sql:`
|
|
911
965
|
INSERT INTO request_events (id, user_id, source, status, query, location, result_count, result, error)
|
|
912
966
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
913
|
-
`,args:[t,e.userId,e.source,e.status,e.query,e.location??null,e.resultCount??null,Ze(e.result),e.error??null]}),t}async function
|
|
967
|
+
`,args:[t,e.userId,e.source,e.status,e.query,e.location??null,e.resultCount??null,Ze(e.result),e.error??null]}),t}async function Nr(e,t=100){return(await n().execute({sql:`
|
|
914
968
|
SELECT id, user_id, source, status, query, location, result_count, NULL AS result, error, created_at
|
|
915
969
|
FROM request_events
|
|
916
970
|
WHERE user_id = ?
|
|
917
971
|
ORDER BY created_at DESC
|
|
918
972
|
LIMIT ?
|
|
919
|
-
`,args:[e,t]})).rows.map(s=>et(s))}function Le(e){if(e==null)return{};try{let t=JSON.parse(String(e));return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function
|
|
973
|
+
`,args:[e,t]})).rows.map(s=>et(s))}function Le(e){if(e==null)return{};try{let t=JSON.parse(String(e));return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function Y(e){return{id:String(e.id),user_id:Number(e.user_id),workflow_id:String(e.workflow_id),name:String(e.name),input:Le(e.input_json),cadence:String(e.cadence),cron_expr:e.cron_expr!=null?String(e.cron_expr):null,timezone:String(e.timezone??"UTC"),webhook_url:e.webhook_url!=null?String(e.webhook_url):null,status:String(e.status),next_run_at:e.next_run_at!=null?String(e.next_run_at):null,last_run_at:e.last_run_at!=null?String(e.last_run_at):null,created_at:String(e.created_at),updated_at:String(e.updated_at)}}function $(e){return{id:String(e.id),user_id:Number(e.user_id),schedule_id:e.schedule_id!=null?String(e.schedule_id):null,workflow_id:String(e.workflow_id),input:Le(e.input_json),status:String(e.status),manifest:e.manifest_json!=null?F(e.manifest_json):null,error_message:e.error_message!=null?String(e.error_message):null,queued_at:String(e.queued_at),started_at:e.started_at!=null?String(e.started_at):null,completed_at:e.completed_at!=null?String(e.completed_at):null,idempotency_key:e.idempotency_key!=null?String(e.idempotency_key):null,step_index:e.step_index!=null?Number(e.step_index):0,total_steps:e.total_steps!=null?Number(e.total_steps):null,step_log:Se(e.step_log_json),webhook_url:e.webhook_url!=null?String(e.webhook_url):null}}function Se(e){if(e==null)return[];try{let t=JSON.parse(String(e));return Array.isArray(t)?t:[]}catch{return[]}}function Re(e){return{id:String(e.id),run_id:String(e.run_id),user_id:Number(e.user_id),kind:String(e.kind),label:String(e.label),path:String(e.path),content_type:String(e.content_type),bytes:e.bytes!=null?Number(e.bytes):null,rows_count:e.rows_count!=null?Number(e.rows_count):null,content:e.content!=null?String(e.content):null,created_at:String(e.created_at)}}async function br(e){let t=g();await n().execute({sql:`
|
|
920
974
|
INSERT INTO workflow_schedules (
|
|
921
975
|
id, user_id, workflow_id, name, input_json, cadence, timezone, webhook_url, next_run_at
|
|
922
976
|
)
|
|
923
977
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
924
|
-
`,args:[t,e.userId,e.workflowId,e.name,JSON.stringify(e.workflowInput),e.cadence,e.timezone??"UTC",e.webhookUrl??null,e.nextRunAt??null]});let r=await B(t,e.userId);if(!r)throw new Error("Failed to create workflow schedule");return r}async function B(e,t){let r=t==null?await n().execute({sql:"SELECT * FROM workflow_schedules WHERE id = ? AND status != ? LIMIT 1",args:[e,"deleted"]}):await n().execute({sql:"SELECT * FROM workflow_schedules WHERE id = ? AND user_id = ? AND status != ? LIMIT 1",args:[e,t,"deleted"]});return r.rows[0]?
|
|
978
|
+
`,args:[t,e.userId,e.workflowId,e.name,JSON.stringify(e.workflowInput),e.cadence,e.timezone??"UTC",e.webhookUrl??null,e.nextRunAt??null]});let r=await B(t,e.userId);if(!r)throw new Error("Failed to create workflow schedule");return r}async function B(e,t){let r=t==null?await n().execute({sql:"SELECT * FROM workflow_schedules WHERE id = ? AND status != ? LIMIT 1",args:[e,"deleted"]}):await n().execute({sql:"SELECT * FROM workflow_schedules WHERE id = ? AND user_id = ? AND status != ? LIMIT 1",args:[e,t,"deleted"]});return r.rows[0]?Y(r.rows[0]):null}async function Lr(e){return(await n().execute({sql:"SELECT * FROM workflow_schedules WHERE user_id = ? AND status != 'deleted' ORDER BY created_at DESC LIMIT 100",args:[e]})).rows.map(r=>Y(r))}async function Sr(e){let t=[],r=[];return e.name!==void 0&&(t.push("name = ?"),r.push(e.name)),e.status!==void 0&&(t.push("status = ?"),r.push(e.status)),e.workflowInput!==void 0&&(t.push("input_json = ?"),r.push(JSON.stringify(e.workflowInput))),e.cadence!==void 0&&(t.push("cadence = ?"),r.push(e.cadence)),e.timezone!==void 0&&(t.push("timezone = ?"),r.push(e.timezone)),e.webhookUrl!==void 0&&(t.push("webhook_url = ?"),r.push(e.webhookUrl)),e.nextRunAt!==void 0&&(t.push("next_run_at = ?"),r.push(e.nextRunAt)),t.length===0||(t.push("updated_at = datetime('now')"),await n().execute({sql:`UPDATE workflow_schedules SET ${t.join(", ")} WHERE id = ? AND user_id = ? AND status != 'deleted'`,args:[...r,e.id,e.userId]})),B(e.id,e.userId)}async function Rr(e,t){return(await n().execute({sql:"UPDATE workflow_schedules SET status = 'deleted', updated_at = datetime('now') WHERE id = ? AND user_id = ? AND status != 'deleted'",args:[e,t]})).rowsAffected>0}async function Ar(e,t=10){return(await n().execute({sql:`
|
|
925
979
|
SELECT * FROM workflow_schedules
|
|
926
980
|
WHERE status = 'active' AND next_run_at IS NOT NULL AND next_run_at <= ?
|
|
927
981
|
ORDER BY next_run_at ASC
|
|
928
982
|
LIMIT ?
|
|
929
|
-
`,args:[e,t]})).rows.map(s=>
|
|
983
|
+
`,args:[e,t]})).rows.map(s=>Y(s))}async function wr(e,t,r){await n().execute({sql:"UPDATE workflow_schedules SET last_run_at = ?, next_run_at = ?, updated_at = datetime('now') WHERE id = ?",args:[t,r,e]})}async function fr(e){let t=e.id??g(),r=[t,e.userId,e.scheduleId??null,e.workflowId,JSON.stringify(e.workflowInput),e.idempotencyKey??null,e.webhookUrl??null,e.totalSteps??null];try{await n().execute({sql:`
|
|
930
984
|
INSERT INTO workflow_runs (id, user_id, schedule_id, workflow_id, input_json, idempotency_key, webhook_url, total_steps)
|
|
931
985
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
932
|
-
`,args:r})}catch(i){if(e.idempotencyKey){let a=await rt(e.idempotencyKey);if(a)return a}throw i}let s=await tt(t,e.userId);if(!s)throw new Error("Failed to create workflow run");return s}async function tt(e,t){let r=t==null?await n().execute({sql:"SELECT * FROM workflow_runs WHERE id = ? LIMIT 1",args:[e]}):await n().execute({sql:"SELECT * FROM workflow_runs WHERE id = ? AND user_id = ? LIMIT 1",args:[e,t]});return r.rows[0]
|
|
986
|
+
`,args:r})}catch(i){if(e.idempotencyKey){let a=await rt(e.idempotencyKey);if(a)return a}throw i}let s=await tt(t,e.userId);if(!s)throw new Error("Failed to create workflow run");return s}async function tt(e,t){let r=t==null?await n().execute({sql:"SELECT * FROM workflow_runs WHERE id = ? LIMIT 1",args:[e]}):await n().execute({sql:"SELECT * FROM workflow_runs WHERE id = ? AND user_id = ? LIMIT 1",args:[e,t]});return r.rows[0]?$(r.rows[0]):null}async function rt(e){let t=await n().execute({sql:"SELECT * FROM workflow_runs WHERE idempotency_key = ? LIMIT 1",args:[e]});return t.rows[0]?$(t.rows[0]):null}async function Or(e,t=50){return(await n().execute({sql:"SELECT * FROM workflow_runs WHERE user_id = ? ORDER BY queued_at DESC LIMIT ?",args:[e,t]})).rows.map(s=>$(s))}async function hr(e){await n().execute({sql:"UPDATE workflow_runs SET status = 'running', started_at = COALESCE(started_at, datetime('now')) WHERE id = ?",args:[e]})}async function xr(e,t,r){await n().execute({sql:"UPDATE workflow_runs SET status = ?, manifest_json = ?, completed_at = datetime('now') WHERE id = ?",args:[t,JSON.stringify(r),e]})}async function yr(e,t,r){await n().execute({sql:"UPDATE workflow_runs SET status = 'failed', error_message = ?, manifest_json = ?, completed_at = datetime('now') WHERE id = ?",args:[t,r==null?null:JSON.stringify(r),e]})}function st(e){return e==="html_report"?"text/html; charset=utf-8":e==="csv"?"text/csv; charset=utf-8":e==="json"?"application/json; charset=utf-8":"text/plain; charset=utf-8"}async function Ae(e,t,r){await n().execute({sql:`
|
|
933
987
|
INSERT INTO workflow_artifacts (id, run_id, user_id, kind, label, path, content_type, bytes, rows_count, content)
|
|
934
988
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
935
|
-
`,args:[g(),e,t,r.kind,r.label,r.path,st(r.kind),r.bytes??null,r.rows??null,r.content??null]})}async function
|
|
989
|
+
`,args:[g(),e,t,r.kind,r.label,r.path,st(r.kind),r.bytes??null,r.rows??null,r.content??null]})}async function Ir(e,t,r){await n().execute({sql:"DELETE FROM workflow_artifacts WHERE run_id = ? AND user_id = ?",args:[e,t]});for(let s of r)await Ae(e,t,s);return we(e,t)}async function Cr(e,t,r){for(let s of r)await Ae(e,t,s);return we(e,t)}async function Ur(e,t){let s=(t==null?await n().execute({sql:"SELECT step_index, total_steps, step_state_json, step_log_json FROM workflow_runs WHERE id = ? LIMIT 1",args:[e]}):await n().execute({sql:"SELECT step_index, total_steps, step_state_json, step_log_json FROM workflow_runs WHERE id = ? AND user_id = ? LIMIT 1",args:[e,t]})).rows[0];return s?{stepIndex:s.step_index!=null?Number(s.step_index):0,totalSteps:s.total_steps!=null?Number(s.total_steps):null,state:s.step_state_json!=null?F(s.step_state_json):null,stepLog:Se(s.step_log_json)}:null}async function Dr(e,t){let r=[...t.appendLog,t.logEntry];await n().execute({sql:"UPDATE workflow_runs SET status = ?, step_index = ?, total_steps = ?, step_state_json = ?, step_log_json = ?, started_at = COALESCE(started_at, datetime('now')) WHERE id = ?",args:[t.status,t.stepIndex,t.totalSteps,JSON.stringify(t.state??null),JSON.stringify(r),e]})}async function we(e,t){return(await n().execute({sql:"SELECT * FROM workflow_artifacts WHERE run_id = ? AND user_id = ? ORDER BY created_at ASC",args:[e,t]})).rows.map(s=>Re(s))}async function kr(e,t){let r=await n().execute({sql:"SELECT * FROM workflow_artifacts WHERE id = ? AND user_id = ? LIMIT 1",args:[e,t]});return r.rows[0]?Re(r.rows[0]):null}async function vr(e){await n().execute({sql:`
|
|
936
990
|
INSERT INTO workflow_webhook_deliveries (
|
|
937
991
|
id, run_id, schedule_id, user_id, webhook_url, status, attempts, last_error, delivered_at
|
|
938
992
|
)
|
|
939
993
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
940
|
-
`,args:[g(),e.runId,e.scheduleId??null,e.userId,e.webhookUrl,e.status,e.attempts,e.lastError??null,e.status==="delivered"?new Date().toISOString():null]})}async function
|
|
994
|
+
`,args:[g(),e.runId,e.scheduleId??null,e.userId,e.webhookUrl,e.status,e.attempts,e.lastError??null,e.status==="delivered"?new Date().toISOString():null]})}async function Xr(){let e=await n().execute("SELECT COUNT(*) as n FROM users WHERE active = 1");return Number(e.rows[0]?.n??0)}async function Mr(e){let t=await n().execute({sql:"SELECT COUNT(*) as n FROM jobs WHERE user_id = ? AND (status = 'pending' OR (status = 'running' AND started_at > datetime('now', '-10 minutes')))",args:[e]});return Number(t.rows[0]?.n??0)}async function Fr(){let e=n(),t=await e.execute(`
|
|
941
995
|
SELECT * FROM jobs
|
|
942
996
|
WHERE status = 'pending'
|
|
943
997
|
AND COALESCE(json_extract(options, '$.executionOwner'), 'cron') NOT IN ('direct', 'inngest')
|
|
944
998
|
ORDER BY created_at
|
|
945
999
|
LIMIT 1
|
|
946
|
-
`),r=t.rows[0]?
|
|
1000
|
+
`),r=t.rows[0]?S(t.rows[0]):void 0;return r?(await e.execute({sql:"UPDATE jobs SET status = 'running', started_at = datetime('now') WHERE id = ? AND status = 'pending'",args:[r.id]})).rowsAffected===0?void 0:{...r,status:"running"}:void 0}var J=45e3;async function Pr(e){let t=n(),r=await G(e);if(!r||r.options.executionOwner!=="direct"||r.options.serpOnly===!0)return;let s=Math.max(0,Number(r.options.paaRecoveryCount??0));if(r.status!=="running"){if(r.status==="pending"){let i=g(),a=new Date().toISOString(),u=new Date(Date.now()+J).toISOString();return(await t.execute({sql:`UPDATE jobs
|
|
947
1001
|
SET status = 'running', started_at = datetime('now'), error = NULL,
|
|
948
1002
|
options = json_set(options,
|
|
949
1003
|
'$.paaLeaseToken', ?,
|
|
950
1004
|
'$.paaLeaseExpiresAt', ?,
|
|
951
1005
|
'$.paaLastDispatchAt', ?)
|
|
952
|
-
WHERE id = ? AND status = 'pending'`,args:[i,u,a,e]})).rowsAffected===0?void 0:{job:{...r,status:"running",started_at:a,options:{...r.options,paaLeaseToken:i,paaLeaseExpiresAt:u,paaLastDispatchAt:a}},leaseToken:i,recoveryCount:s}}return{job:r,leaseToken:null,recoveryCount:s}}}async function
|
|
953
|
-
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[JSON.stringify(r),s,e,t]})).rowsAffected===1}async function
|
|
954
|
-
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[r,e,t]})).rowsAffected===1}async function
|
|
1006
|
+
WHERE id = ? AND status = 'pending'`,args:[i,u,a,e]})).rowsAffected===0?void 0:{job:{...r,status:"running",started_at:a,options:{...r.options,paaLeaseToken:i,paaLeaseExpiresAt:u,paaLastDispatchAt:a}},leaseToken:i,recoveryCount:s}}return{job:r,leaseToken:null,recoveryCount:s}}}async function Hr(e,t){return(await n().execute({sql:"UPDATE jobs SET result = ? WHERE id = ? AND status = 'running'",args:[JSON.stringify(t),e]})).rowsAffected===1}async function Wr(e,t,r){let s=new Date(Date.now()+J).toISOString();return(await n().execute({sql:`UPDATE jobs SET result = ?, options = json_set(options, '$.paaLeaseExpiresAt', ?)
|
|
1007
|
+
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[JSON.stringify(r),s,e,t]})).rowsAffected===1}async function qr(e,t){let r=new Date(Date.now()+J).toISOString();return(await n().execute({sql:`UPDATE jobs SET options = json_set(options, '$.paaLeaseExpiresAt', ?)
|
|
1008
|
+
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[r,e,t]})).rowsAffected===1}async function jr(e,t,r){return(await n().execute({sql:`UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL,
|
|
955
1009
|
completed_at = datetime('now'),
|
|
956
1010
|
options = json_set(options, '$.paaLeaseExpiresAt', NULL)
|
|
957
|
-
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[JSON.stringify(r),e,t]})).rowsAffected===1}async function
|
|
1011
|
+
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[JSON.stringify(r),e,t]})).rowsAffected===1}async function Br(e,t,r,s){return(await n().execute({sql:`UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now'),
|
|
958
1012
|
options = json_set(options, '$.paaLeaseExpiresAt', NULL)
|
|
959
|
-
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[r,
|
|
1013
|
+
WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[r,w(s),e,t]})).rowsAffected===1}async function Gr(e,t){let r=new Date().toISOString();return(await n().execute({sql:`UPDATE jobs SET status = 'pending', started_at = NULL,
|
|
960
1014
|
result = CASE WHEN json_valid(result) THEN json_set(result,
|
|
961
1015
|
'$.progress.lifecycle.discoveryStatus', 'interrupted',
|
|
962
1016
|
'$.progress.lifecycle.completionReason', 'The previous worker lease expired; the same job is recovering automatically.',
|
|
@@ -972,28 +1026,28 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
972
1026
|
datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
|
|
973
1027
|
OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
|
|
974
1028
|
)
|
|
975
|
-
AND COALESCE(json_extract(options, '$.paaRecoveryCount'), 0) < ?`,args:[r,e,Math.max(0,Math.trunc(t))]})).rowsAffected===1}async function
|
|
1029
|
+
AND COALESCE(json_extract(options, '$.paaRecoveryCount'), 0) < ?`,args:[r,e,Math.max(0,Math.trunc(t))]})).rowsAffected===1}async function Yr(e,t){return(await n().execute({sql:`UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL, completed_at = datetime('now')
|
|
976
1030
|
WHERE id = ? AND status = 'running'
|
|
977
1031
|
AND (
|
|
978
1032
|
datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
|
|
979
1033
|
OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
|
|
980
|
-
)`,args:[JSON.stringify(t),e]})).rowsAffected===1}async function
|
|
1034
|
+
)`,args:[JSON.stringify(t),e]})).rowsAffected===1}async function $r(e,t,r){return(await n().execute({sql:`UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now')
|
|
981
1035
|
WHERE id = ? AND status = 'running'
|
|
982
1036
|
AND (
|
|
983
1037
|
datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
|
|
984
1038
|
OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
|
|
985
|
-
)`,args:[t,
|
|
1039
|
+
)`,args:[t,w(r),e]})).rowsAffected===1}async function Jr(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await n().execute({sql:`SELECT * FROM jobs
|
|
986
1040
|
WHERE status IN ('done', 'failed', 'cancelled')
|
|
987
1041
|
AND json_extract(options, '$.executionOwner') IN ('direct', 'inngest')
|
|
988
1042
|
AND json_extract(options, '$.billingDebitKey') IS NOT NULL
|
|
989
1043
|
AND json_extract(options, '$.billingSettledAt') IS NULL
|
|
990
1044
|
ORDER BY completed_at DESC
|
|
991
|
-
LIMIT ?`,args:[t]})).rows.map(s=>
|
|
1045
|
+
LIMIT ?`,args:[t]})).rows.map(s=>f(S(s)))}async function Kr(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await n().execute({sql:`SELECT * FROM jobs
|
|
992
1046
|
WHERE status = 'running'
|
|
993
1047
|
AND started_at <= datetime('now', '-15 minutes')
|
|
994
1048
|
AND json_extract(options, '$.executionOwner') IN ('direct', 'inngest')
|
|
995
1049
|
ORDER BY started_at
|
|
996
|
-
LIMIT ?`,args:[t]})).rows.map(s=>
|
|
1050
|
+
LIMIT ?`,args:[t]})).rows.map(s=>f(S(s)))}async function Vr(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await n().execute({sql:`SELECT * FROM jobs
|
|
997
1051
|
WHERE json_extract(options, '$.executionOwner') = 'direct'
|
|
998
1052
|
AND json_extract(options, '$.serpOnly') IS NOT 1
|
|
999
1053
|
AND (
|
|
@@ -1006,11 +1060,24 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1006
1060
|
AND datetime(COALESCE(json_extract(options, '$.paaLastDispatchAt'), '1970-01-01')) <= datetime('now', '-30 seconds'))
|
|
1007
1061
|
)
|
|
1008
1062
|
ORDER BY COALESCE(started_at, created_at)
|
|
1009
|
-
LIMIT ?`,args:[t]})).rows.map(s=>
|
|
1063
|
+
LIMIT ?`,args:[t]})).rows.map(s=>f(S(s)))}async function zr(e,t,r=new Date().toISOString()){if(!Number.isSafeInteger(t)||t<0)throw new Error("job billed amount must be a non-negative integer");return(await n().execute({sql:`UPDATE jobs
|
|
1010
1064
|
SET options = json_set(options, '$.billingSettledAt', ?, '$.billedMc', ?)
|
|
1011
|
-
WHERE id = ?`,args:[r,t,e]})).rowsAffected===1}async function
|
|
1012
|
-
WHERE id = ? AND status = 'running'`,args:[JSON.stringify(t),e]})).rowsAffected===1}async function
|
|
1013
|
-
WHERE id = ? AND status = 'running'`,args:[t,
|
|
1065
|
+
WHERE id = ?`,args:[r,t,e]})).rowsAffected===1}async function Qr(e,t){await n().execute({sql:"UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL, completed_at = datetime('now') WHERE id = ?",args:[JSON.stringify(t),e]})}async function Zr(e,t){return(await n().execute({sql:`UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL, completed_at = datetime('now')
|
|
1066
|
+
WHERE id = ? AND status = 'running'`,args:[JSON.stringify(t),e]})).rowsAffected===1}async function es(e,t,r){await n().execute({sql:"UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now') WHERE id = ?",args:[t,w(r),e]})}async function ts(e,t,r){return(await n().execute({sql:`UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now')
|
|
1067
|
+
WHERE id = ? AND status = 'running'`,args:[t,w(r),e]})).rowsAffected===1}async function rs(e,t,r){await n().execute({sql:"UPDATE jobs SET status = 'cancelled', error = ?, public_error_json = ?, completed_at = datetime('now') WHERE id = ?",args:[t,w(r),e]})}function K(e){return{id:String(e.id),user_id:Number(e.user_id),status:String(e.status),entity_name:String(e.entity_name),entity_type:String(e.entity_type),url:e.url!=null?String(e.url):null,request:String(e.request),result:e.result!=null?String(e.result):null,error:e.error!=null?String(e.error):null,created_at:String(e.created_at),updated_at:String(e.updated_at)}}function nt(e){return{id:Number(e.id),job_id:String(e.job_id),phase:String(e.phase),output:String(e.output),created_at:String(e.created_at)}}async function ss(e,t,r,s,i,a){await n().execute({sql:"INSERT INTO kpo_jobs (id, user_id, status, entity_name, entity_type, url, request) VALUES (?, ?, 'pending', ?, ?, ?, ?)",args:[e,t,r,s,a??null,JSON.stringify(i)]})}async function ns(){let t=await n().execute("UPDATE kpo_jobs SET status='running', updated_at=datetime('now') WHERE id = (SELECT id FROM kpo_jobs WHERE status='pending' ORDER BY created_at ASC LIMIT 1) RETURNING *");return t.rowsAffected===0?null:t.rows[0]?K(t.rows[0]):null}async function is(e){let t=await n().execute({sql:"SELECT * FROM kpo_jobs WHERE id = ?",args:[e]});return t.rows[0]?K(t.rows[0]):null}async function as(e,t){await n().execute({sql:"UPDATE kpo_jobs SET status = ?, updated_at = datetime('now') WHERE id = ?",args:[t,e]})}async function os(e,t){await n().execute({sql:"UPDATE kpo_jobs SET status = 'done', result = ?, updated_at = datetime('now') WHERE id = ?",args:[JSON.stringify(t),e]})}async function us(e,t){await n().execute({sql:"UPDATE kpo_jobs SET status = 'failed', error = ?, updated_at = datetime('now') WHERE id = ?",args:[t,e]})}async function cs(e,t,r){await n().execute({sql:"INSERT INTO kpo_phase_log (job_id, phase, output) VALUES (?, ?, ?)",args:[e,t,JSON.stringify(r)]})}async function _s(e){return(await n().execute({sql:"SELECT * FROM kpo_phase_log WHERE job_id = ? ORDER BY created_at ASC",args:[e]})).rows.map(r=>nt(r))}async function ds(e){return(e!=null?await n().execute({sql:"SELECT * FROM kpo_jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50",args:[e]}):await n().execute("SELECT * FROM kpo_jobs ORDER BY created_at DESC LIMIT 50")).rows.map(r=>K(r))}async function ls(e){let t=await n().execute({sql:"SELECT * FROM users WHERE stripe_customer_id = ? AND active = 1",args:[e]});return t.rows[0]?L(t.rows[0]):void 0}async function Es(e,t){await n().execute({sql:"UPDATE users SET stripe_customer_id = ? WHERE id = ?",args:[t,e]})}async function Ts(e,t){if(!Number.isSafeInteger(t)||t<0)throw new Error("extra concurrency slots must be a non-negative safe integer");await it(e,Math.ceil(t/2))}async function it(e,t){if(!Number.isSafeInteger(t)||t<0)throw new Error("concurrency pack quantity must be a non-negative safe integer");await n().execute({sql:"UPDATE users SET concurrency_pack_quantity = ?, extra_concurrency_slots = ? WHERE id = ?",args:[t,t*2,e]})}async function ps(e,t){await n().execute({sql:"UPDATE users SET concurrency_stripe_sub_id = ? WHERE id = ?",args:[t,e]})}async function ms(e,t,r,s){await n().execute({sql:"UPDATE users SET subscription_tier = ?, subscription_concurrency = ?, subscription_id = ? WHERE id = ?",args:[t,Math.max(0,Math.round(r)),s,e]})}async function gs(e){if(!e.invoiceId||e.invoiceId.length>500)throw new Error("invoice id is required and must be bounded");if(!Number.isSafeInteger(e.creditsMc)||e.creditsMc<=0)throw new Error("subscription credit amount must be a positive integer");await R(e.userId);let t=n(),r=e.neverExpires?"9999-12-31 23:59:59":null,s=await t.batch([{sql:`INSERT OR IGNORE INTO ledger (user_id, amount_mc, operation, description, stripe_pi)
|
|
1068
|
+
VALUES (?, ?, 'subscription', ?, ?)`,args:[e.userId,e.creditsMc,e.description,e.invoiceId]},{sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, stripe_pi, expires_at, never_expires)
|
|
1069
|
+
SELECT ?, ?, ?, 'subscription', ?, COALESCE(?, datetime('now', ?)), ?
|
|
1070
|
+
WHERE changes() = 1`,args:[e.userId,e.creditsMc,e.creditsMc,e.invoiceId,r,C,e.neverExpires?1:0]},{sql:"UPDATE users SET balance_mc = balance_mc + ? WHERE id = ? AND changes() = 1",args:[e.creditsMc,e.userId]},{sql:`UPDATE users
|
|
1071
|
+
SET subscription_tier = ?, subscription_concurrency = ?, subscription_id = ?,
|
|
1072
|
+
memory_plan = CASE WHEN ? IS NOT NULL THEN ? ELSE memory_plan END,
|
|
1073
|
+
memory_subscription_id = CASE WHEN ? IS NOT NULL THEN NULL ELSE memory_subscription_id END
|
|
1074
|
+
WHERE id = ?
|
|
1075
|
+
AND EXISTS (
|
|
1076
|
+
SELECT 1 FROM ledger
|
|
1077
|
+
WHERE stripe_pi = ? AND user_id = ? AND amount_mc = ? AND operation = 'subscription'
|
|
1078
|
+
)`,args:[e.tier,Math.max(0,Math.round(e.concurrency)),e.subscriptionId,e.includedMemoryPlan,e.includedMemoryPlan,e.includedMemoryPlan,e.userId,e.invoiceId,e.userId,e.creditsMc]}],"write"),a=(await t.execute({sql:`SELECT l.user_id, l.amount_mc, l.operation, u.balance_mc
|
|
1079
|
+
FROM ledger l JOIN users u ON u.id = l.user_id
|
|
1080
|
+
WHERE l.stripe_pi = ? LIMIT 1`,args:[e.invoiceId]})).rows[0];if(!a||Number(a.user_id)!==e.userId||Number(a.amount_mc)!==e.creditsMc||String(a.operation)!=="subscription")throw new Error("invoice idempotency key conflicts with an existing grant");return{granted:s[0]?.rowsAffected===1,balance_mc:Number(a.balance_mc??0)}}function at(e){return{user_id:Number(e.user_id),stripe_subscription_id:e.stripe_subscription_id!=null?String(e.stripe_subscription_id):null,stripe_subscription_item_id:e.stripe_subscription_item_id!=null?String(e.stripe_subscription_item_id):null,price_id:e.price_id!=null?String(e.price_id):null,quantity:Math.max(0,Number(e.quantity??0)),status:["pending","synced","blocked","error"].includes(String(e.status))?String(e.status):"error",last_error_code:e.last_error_code!=null?String(e.last_error_code):null,checked_at:String(e.checked_at),synced_at:e.synced_at!=null?String(e.synced_at):null,updated_at:String(e.updated_at)}}async function ot(e){let r=(await n().execute({sql:"SELECT * FROM connected_account_billing WHERE user_id = ? LIMIT 1",args:[e]})).rows[0];return r?at(r):null}async function Ns(e){let t=Math.max(0,Math.round(e.quantity));await n().execute({sql:`INSERT INTO connected_account_billing
|
|
1014
1081
|
(user_id, stripe_subscription_id, stripe_subscription_item_id, price_id, quantity, status, last_error_code, checked_at, synced_at, updated_at)
|
|
1015
1082
|
VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'), CASE WHEN ? THEN datetime('now') ELSE NULL END, datetime('now'))
|
|
1016
1083
|
ON CONFLICT(user_id) DO UPDATE SET
|
|
@@ -1022,14 +1089,14 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1022
1089
|
last_error_code = excluded.last_error_code,
|
|
1023
1090
|
checked_at = datetime('now'),
|
|
1024
1091
|
synced_at = CASE WHEN ? THEN datetime('now') ELSE connected_account_billing.synced_at END,
|
|
1025
|
-
updated_at = datetime('now')`,args:[e.userId,e.stripeSubscriptionId,e.stripeSubscriptionItemId,e.priceId,t,e.status,e.lastErrorCode??null,e.synced===!0?1:0,e.synced===!0?1:0]});let r=await ot(e.userId);if(!r)throw new Error("connected account billing state was not persisted");return r}async function
|
|
1092
|
+
updated_at = datetime('now')`,args:[e.userId,e.stripeSubscriptionId,e.stripeSubscriptionItemId,e.priceId,t,e.status,e.lastErrorCode??null,e.synced===!0?1:0,e.synced===!0?1:0]});let r=await ot(e.userId);if(!r)throw new Error("connected account billing state was not persisted");return r}async function bs(e=60,t=20){let r=`-${Math.max(1,Math.round(e))} minutes`;return(await n().execute({sql:`SELECT u.*
|
|
1026
1093
|
FROM users u
|
|
1027
1094
|
LEFT JOIN connected_account_billing b ON b.user_id = u.id
|
|
1028
1095
|
WHERE u.active = 1
|
|
1029
1096
|
AND u.subscription_id IS NOT NULL
|
|
1030
1097
|
AND (b.checked_at IS NULL OR b.checked_at <= datetime('now', ?))
|
|
1031
1098
|
ORDER BY COALESCE(b.checked_at, u.created_at) ASC
|
|
1032
|
-
LIMIT ?`,args:[r,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(i=>L(i))}async function
|
|
1099
|
+
LIMIT ?`,args:[r,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(i=>L(i))}async function Ls(e,t,r){await n().execute({sql:"UPDATE users SET memory_plan = ?, memory_subscription_id = ? WHERE id = ?",args:[t,r,e]})}async function Ss(e){let r=(await n().execute({sql:"SELECT memory_plan, memory_subscription_id FROM users WHERE id = ?",args:[e]})).rows[0];return{plan:r?.memory_plan!=null?String(r.memory_plan):"free",memory_subscription_id:r?.memory_subscription_id!=null?String(r.memory_subscription_id):null}}async function Rs(e){let r=(await n().execute({sql:"SELECT memory_provisioned FROM users WHERE id = ?",args:[e]})).rows[0];return Number(r?.memory_provisioned??0)===1}async function As(e,t){await n().execute({sql:"UPDATE users SET memory_provisioned = ? WHERE id = ?",args:[t?1:0,e]})}async function ws(e){let t=await n().execute({sql:"SELECT * FROM users WHERE memory_subscription_id = ? AND active = 1",args:[e]});return t.rows[0]?L(t.rows[0]):void 0}var C="+3 months";async function R(e){return(await n().execute({sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, expires_at)
|
|
1033
1100
|
SELECT ?, legacy.balance_mc, legacy.balance_mc, 'migration', datetime('now', ?)
|
|
1034
1101
|
FROM (
|
|
1035
1102
|
SELECT COALESCE(SUM(amount_mc), 0) AS balance_mc
|
|
@@ -1043,7 +1110,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1043
1110
|
)
|
|
1044
1111
|
AND NOT EXISTS (
|
|
1045
1112
|
SELECT 1 FROM credit_lots WHERE user_id = ?
|
|
1046
|
-
)`,args:[e,
|
|
1113
|
+
)`,args:[e,C,e,e,D,e]})).rowsAffected}async function fs(){let e=n(),t=await e.execute({sql:`SELECT id
|
|
1047
1114
|
FROM credit_lots
|
|
1048
1115
|
WHERE remaining_mc > 0
|
|
1049
1116
|
AND never_expires = 0
|
|
@@ -1065,22 +1132,22 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1065
1132
|
FROM credit_lot_expirations
|
|
1066
1133
|
WHERE lot_id = ? AND claim_token = ?`,args:[d,E]})}let i=await e.batch(s,"write"),a=r.filter(_=>i[_.insertResultIndex]?.rowsAffected===1).map(_=>_.token);if(a.length===0)return{expired_lots:0,expired_mc:0};let u=a.map(()=>"?").join(", "),c=await e.execute({sql:`SELECT user_id, amount_mc
|
|
1067
1134
|
FROM credit_lot_expirations
|
|
1068
|
-
WHERE claim_token IN (${u})`,args:a}),o=new Set(c.rows.map(_=>Number(_.user_id)));for(let _ of o)await fe(_);return{expired_lots:c.rows.length,expired_mc:c.rows.reduce((_,d)=>_+Number(d.amount_mc),0)}}async function
|
|
1135
|
+
WHERE claim_token IN (${u})`,args:a}),o=new Set(c.rows.map(_=>Number(_.user_id)));for(let _ of o)await fe(_);return{expired_lots:c.rows.length,expired_mc:c.rows.reduce((_,d)=>_+Number(d.amount_mc),0)}}async function Os(){let e=n(),t=await e.execute({sql:`SELECT DISTINCT u.id AS user_id
|
|
1069
1136
|
FROM users u
|
|
1070
1137
|
JOIN ledger l ON l.user_id = u.id
|
|
1071
1138
|
WHERE l.created_at < ?
|
|
1072
|
-
AND NOT EXISTS (SELECT 1 FROM credit_lots WHERE user_id = u.id)`,args:[
|
|
1139
|
+
AND NOT EXISTS (SELECT 1 FROM credit_lots WHERE user_id = u.id)`,args:[D]}),r=0,s=0;for(let i of t.rows){let a=Number(i.user_id);if(await R(a)===0)continue;let c=await e.execute({sql:`SELECT amount_mc FROM credit_lots
|
|
1073
1140
|
WHERE user_id = ? AND source = 'migration'
|
|
1074
|
-
ORDER BY id DESC LIMIT 1`,args:[a]}),o=Number(c.rows[0]?.amount_mc??0);await fe(a),r+=1,s+=o}return{migrated:r,total_mc:s}}async function
|
|
1141
|
+
ORDER BY id DESC LIMIT 1`,args:[a]}),o=Number(c.rows[0]?.amount_mc??0);await fe(a),r+=1,s+=o}return{migrated:r,total_mc:s}}async function hs(e,t,r,s,i,a){let u=n();await R(e);let c=a?.neverExpires;if(c===void 0&&t>0){let E=await u.execute({sql:"SELECT subscription_tier FROM users WHERE id = ? LIMIT 1",args:[e]});c=String(E.rows[0]?.subscription_tier??"").startsWith("sonic")}let o=c?"9999-12-31 23:59:59":null;if(i){let E=[{sql:"INSERT OR IGNORE INTO ledger (user_id, amount_mc, operation, description, stripe_pi) VALUES (?, ?, ?, ?, ?)",args:[e,t,r,s??null,i]}];t>0&&E.push({sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, stripe_pi, expires_at, never_expires)
|
|
1075
1142
|
SELECT ?, ?, ?, ?, ?, COALESCE(?, datetime('now', ?)), ?
|
|
1076
|
-
WHERE changes() = 1`,args:[e,t,t,r,i,o,
|
|
1143
|
+
WHERE changes() = 1`,args:[e,t,t,r,i,o,C,c?1:0]}),E.push({sql:"UPDATE users SET balance_mc = balance_mc + ? WHERE id = ? AND changes() = 1",args:[t,e]}),await u.batch(E,"write");let l=await u.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return Number(l.rows[0]?.balance_mc??0)}let _=[];t>0&&_.push({sql:"INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, stripe_pi, expires_at, never_expires) VALUES (?, ?, ?, ?, ?, COALESCE(?, datetime('now', ?)), ?)",args:[e,t,t,r,null,o,C,c?1:0]}),_.push({sql:"UPDATE users SET balance_mc = balance_mc + ? WHERE id = ?",args:[t,e]}),_.push({sql:"INSERT INTO ledger (user_id, amount_mc, operation, description, stripe_pi) VALUES (?, ?, ?, ?, ?)",args:[e,t,r,s??null,null]}),await u.batch(_,"write");let d=await u.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return Number(d.rows[0]?.balance_mc??0)}async function xs(e,t,r,s,i,a){if(!Number.isSafeInteger(t)||t<=0)throw new Error("idempotent credit amount must be a positive integer");if(!i||i.length>500)throw new Error("idempotent credit key is required and must be bounded");let u=n();await R(e);let c=a?.neverExpires;if(c===void 0){let m=await u.execute({sql:"SELECT subscription_tier FROM users WHERE id = ? LIMIT 1",args:[e]});c=String(m.rows[0]?.subscription_tier??"").startsWith("sonic")}let o=c?"9999-12-31 23:59:59":null,_=async()=>{let m=await u.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return Number(m.rows[0]?.balance_mc??0)},d;try{d=await u.batch([{sql:"INSERT OR IGNORE INTO billing_credits (idempotency_key, user_id, amount_mc, operation, description, status) VALUES (?, ?, ?, ?, ?, 'claimed')",args:[i,e,t,r,s]},{sql:"UPDATE billing_credits SET status = 'applying' WHERE idempotency_key = ? AND user_id = ? AND amount_mc = ? AND operation = ? AND description = ? AND status = 'claimed'",args:[i,e,t,r,s]},{sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, stripe_pi, expires_at, never_expires)
|
|
1077
1144
|
SELECT user_id, amount_mc, amount_mc, operation, NULL, COALESCE(?, datetime('now', ?)), ?
|
|
1078
1145
|
FROM billing_credits
|
|
1079
|
-
WHERE idempotency_key = ? AND status = 'applying'`,args:[o,
|
|
1146
|
+
WHERE idempotency_key = ? AND status = 'applying'`,args:[o,C,c?1:0,i]},{sql:`UPDATE users
|
|
1080
1147
|
SET balance_mc = balance_mc + COALESCE((
|
|
1081
1148
|
SELECT amount_mc FROM billing_credits WHERE idempotency_key = ? AND status = 'applying'
|
|
1082
1149
|
), 0)
|
|
1083
|
-
WHERE id = ?`,args:[i,e]},{sql:"INSERT INTO ledger (user_id, amount_mc, operation, description) SELECT user_id, amount_mc, operation, description FROM billing_credits WHERE idempotency_key = ? AND status = 'applying'",args:[i]},{sql:"UPDATE billing_credits SET status = 'applied', applied_at = datetime('now') WHERE idempotency_key = ? AND status = 'applying'",args:[i]}],"write")}catch(m){try{let T=(await u.execute({sql:"SELECT user_id, amount_mc, operation, description FROM billing_credits WHERE idempotency_key = ? AND status = 'applied' LIMIT 1",args:[i]})).rows[0];if(T&&Number(T.user_id)===e&&Number(T.amount_mc)===t&&String(T.operation)===r&&String(T.description)===s)return{ok:!0,balance_mc:await _(),duplicate:!0}}catch{}throw m}let l=(await u.execute({sql:"SELECT user_id, amount_mc, operation, description, status FROM billing_credits WHERE idempotency_key = ? LIMIT 1",args:[i]})).rows[0];if(!l||Number(l.user_id)!==e||Number(l.amount_mc)!==t||String(l.operation)!==r||String(l.description)!==s)throw new Error("idempotent credit key conflicts with another credit");return{ok:String(l.status)==="applied",balance_mc:await _(),duplicate:d[1]?.rowsAffected===0&&String(l.status)==="applied"}}async function
|
|
1150
|
+
WHERE id = ?`,args:[i,e]},{sql:"INSERT INTO ledger (user_id, amount_mc, operation, description) SELECT user_id, amount_mc, operation, description FROM billing_credits WHERE idempotency_key = ? AND status = 'applying'",args:[i]},{sql:"UPDATE billing_credits SET status = 'applied', applied_at = datetime('now') WHERE idempotency_key = ? AND status = 'applying'",args:[i]}],"write")}catch(m){try{let T=(await u.execute({sql:"SELECT user_id, amount_mc, operation, description FROM billing_credits WHERE idempotency_key = ? AND status = 'applied' LIMIT 1",args:[i]})).rows[0];if(T&&Number(T.user_id)===e&&Number(T.amount_mc)===t&&String(T.operation)===r&&String(T.description)===s)return{ok:!0,balance_mc:await _(),duplicate:!0}}catch{}throw m}let l=(await u.execute({sql:"SELECT user_id, amount_mc, operation, description, status FROM billing_credits WHERE idempotency_key = ? LIMIT 1",args:[i]})).rows[0];if(!l||Number(l.user_id)!==e||Number(l.amount_mc)!==t||String(l.operation)!==r||String(l.description)!==s)throw new Error("idempotent credit key conflicts with another credit");return{ok:String(l.status)==="applied",balance_mc:await _(),duplicate:d[1]?.rowsAffected===0&&String(l.status)==="applied"}}async function ys(e,t){return(await n().execute({sql:"SELECT 1 FROM ledger WHERE user_id = ? AND operation = ? LIMIT 1",args:[e,t]})).rows.length>0}async function Is(e,t){return(await n().execute({sql:"INSERT OR IGNORE INTO free_credit_refreshes (user_id, month) VALUES (?, ?)",args:[e,t]})).rowsAffected>0}async function Cs(e,t,r,s){let i=await ut(e,t,r,s??"",`debit:${g()}`);return{ok:i.ok,balance_mc:i.balance_mc}}async function ut(e,t,r,s,i){if(!Number.isSafeInteger(t)||t<=0)throw new Error("idempotent debit amount must be a positive integer");if(!i||i.length>500)throw new Error("idempotent debit key is required and must be bounded");let a=n();await R(e);let u;try{u=await a.batch([{sql:"UPDATE billing_debits SET amount_mc = ? WHERE idempotency_key = ? AND user_id = ? AND operation = ? AND description = ? AND status = 'claimed'",args:[t,i,e,r,s]},{sql:"INSERT OR IGNORE INTO billing_debits (idempotency_key, user_id, amount_mc, operation, description, status) VALUES (?, ?, ?, ?, ?, 'claimed')",args:[i,e,t,r,s]},{sql:`UPDATE users
|
|
1084
1151
|
SET balance_mc = balance_mc - ?
|
|
1085
1152
|
WHERE id = ?
|
|
1086
1153
|
AND balance_mc >= ?
|
|
@@ -1116,7 +1183,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1116
1183
|
WHERE id IN (
|
|
1117
1184
|
SELECT lot_id FROM billing_debit_allocations WHERE debit_idempotency_key = ?
|
|
1118
1185
|
)
|
|
1119
|
-
AND EXISTS (SELECT 1 FROM billing_debits WHERE idempotency_key = ? AND status = 'applying')`,args:[i,i,i]},{sql:"INSERT INTO ledger (user_id, amount_mc, operation, description) SELECT user_id, -amount_mc, operation, description FROM billing_debits WHERE idempotency_key = ? AND status = 'applying'",args:[i]},{sql:"UPDATE billing_debits SET status = 'applied', applied_at = datetime('now') WHERE idempotency_key = ? AND status = 'applying'",args:[i]}],"write")}catch(d){try{let l=(await a.execute({sql:"SELECT user_id, amount_mc, operation, description, status FROM billing_debits WHERE idempotency_key = ? AND status = 'applied' LIMIT 1",args:[i]})).rows[0];if(l&&Number(l.user_id)===e&&Number(l.amount_mc)===t&&String(l.operation)===r&&String(l.description)===s){let m=await a.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return{ok:!0,balance_mc:Number(m.rows[0]?.balance_mc??0),duplicate:!0}}}catch{}throw d}let o=(await a.execute({sql:"SELECT user_id, amount_mc, operation, description, status FROM billing_debits WHERE idempotency_key = ? LIMIT 1",args:[i]})).rows[0];if(!o||Number(o.user_id)!==e||Number(o.amount_mc)!==t||String(o.operation)!==r||String(o.description)!==s)throw new Error("idempotent debit key conflicts with another debit");let _=await a.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return{ok:String(o.status)==="applied",balance_mc:Number(_.rows[0]?.balance_mc??0),duplicate:u[2]?.rowsAffected===0&&String(o.status)==="applied"}}async function
|
|
1186
|
+
AND EXISTS (SELECT 1 FROM billing_debits WHERE idempotency_key = ? AND status = 'applying')`,args:[i,i,i]},{sql:"INSERT INTO ledger (user_id, amount_mc, operation, description) SELECT user_id, -amount_mc, operation, description FROM billing_debits WHERE idempotency_key = ? AND status = 'applying'",args:[i]},{sql:"UPDATE billing_debits SET status = 'applied', applied_at = datetime('now') WHERE idempotency_key = ? AND status = 'applying'",args:[i]}],"write")}catch(d){try{let l=(await a.execute({sql:"SELECT user_id, amount_mc, operation, description, status FROM billing_debits WHERE idempotency_key = ? AND status = 'applied' LIMIT 1",args:[i]})).rows[0];if(l&&Number(l.user_id)===e&&Number(l.amount_mc)===t&&String(l.operation)===r&&String(l.description)===s){let m=await a.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return{ok:!0,balance_mc:Number(m.rows[0]?.balance_mc??0),duplicate:!0}}}catch{}throw d}let o=(await a.execute({sql:"SELECT user_id, amount_mc, operation, description, status FROM billing_debits WHERE idempotency_key = ? LIMIT 1",args:[i]})).rows[0];if(!o||Number(o.user_id)!==e||Number(o.amount_mc)!==t||String(o.operation)!==r||String(o.description)!==s)throw new Error("idempotent debit key conflicts with another debit");let _=await a.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return{ok:String(o.status)==="applied",balance_mc:Number(_.rows[0]?.balance_mc??0),duplicate:u[2]?.rowsAffected===0&&String(o.status)==="applied"}}async function Us(e,t,r,s,i,a){if(!Number.isSafeInteger(r)||r<0)throw new Error("idempotent debit settlement amount must be a non-negative integer");if(!t||t.length>500)throw new Error("idempotent debit settlement key is required and must be bounded");if(!s||!a)throw new Error("idempotent debit settlement operation and source are required");let u=n();await R(e);let c=`debit-settlement:${U("sha256").update(t).digest("hex")}`,o="wallet_hold_settlement",_=g(),d=JSON.stringify({debitIdempotencyKey:t,refundOperation:s,description:i}),E=async()=>{let T=(await u.execute({sql:`SELECT e.user_id,
|
|
1120
1187
|
e.status,
|
|
1121
1188
|
e.amount_mc AS final_amount_mc,
|
|
1122
1189
|
e.billing_class,
|
|
@@ -1128,7 +1195,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1128
1195
|
WHERE e.idempotency_key = ?
|
|
1129
1196
|
AND d.user_id = e.user_id
|
|
1130
1197
|
AND d.status = 'applied'
|
|
1131
|
-
LIMIT 1`,args:[t,c]})).rows[0];if(!T)return null;if(Number(T.user_id)!==e||String(T.billing_class)!==o||String(T.source_surface)!==a)throw new Error("idempotent debit settlement key conflicts with another settlement");if(String(T.status)!=="settled")return null;let H=Number(T.held_amount_mc),
|
|
1198
|
+
LIMIT 1`,args:[t,c]})).rows[0];if(!T)return null;if(Number(T.user_id)!==e||String(T.billing_class)!==o||String(T.source_surface)!==a)throw new Error("idempotent debit settlement key conflicts with another settlement");if(String(T.status)!=="settled")return null;let H=Number(T.held_amount_mc),A=Number(T.final_amount_mc);if(!Number.isSafeInteger(H)||!Number.isSafeInteger(A)||A<0||A>H)throw new Error("idempotent debit settlement receipt is invalid");let Oe=H-A,V=await u.execute({sql:`WITH ordered AS (
|
|
1132
1199
|
SELECT a.amount_mc,
|
|
1133
1200
|
a.expires_at,
|
|
1134
1201
|
COALESCE(SUM(a.amount_mc) OVER (
|
|
@@ -1144,7 +1211,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1144
1211
|
)
|
|
1145
1212
|
SELECT (SELECT COUNT(*) FROM ordered) AS allocation_count,
|
|
1146
1213
|
COALESCE(SUM(CASE WHEN expires_at > ? THEN refund_mc ELSE 0 END), 0) AS credited_refund_mc
|
|
1147
|
-
FROM refunds`,args:[t,
|
|
1214
|
+
FROM refunds`,args:[t,A,String(T.settled_at)]}),z=Number(V.rows[0]?.allocation_count??0)>0?Number(V.rows[0]?.credited_refund_mc??0):0,he=await u.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return{balance_mc:Number(he.rows[0]?.balance_mc??0),final_amount_mc:A,refund_mc:z,expired_refund_mc:Oe-z,duplicate:!0}},l;try{l=await u.batch([{sql:`INSERT OR IGNORE INTO billing_events
|
|
1148
1215
|
(id, user_id, idempotency_key, billing_class, source_surface, status, amount_mc, metadata)
|
|
1149
1216
|
VALUES (?, ?, ?, ?, ?, 'settling', ?, ?)`,args:[_,e,c,o,a,r,d]},{sql:`WITH ordered AS (
|
|
1150
1217
|
SELECT a.lot_id,
|
|
@@ -1252,7 +1319,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1252
1319
|
WHERE refund_mc > 0`,args:[t,r,t,c,s,i]},{sql:`UPDATE billing_events
|
|
1253
1320
|
SET status = 'settled', settled_at = datetime('now')
|
|
1254
1321
|
WHERE idempotency_key = ?
|
|
1255
|
-
AND status = 'applying'`,args:[c]}],"write")}catch(N){try{let T=await E();if(T)return T}catch{}throw N}let m=await E();if(!m)throw new Error("idempotent debit settlement did not reach a durable settled state");return{...m,duplicate:l[0]?.rowsAffected===0}}async function
|
|
1322
|
+
AND status = 'applying'`,args:[c]}],"write")}catch(N){try{let T=await E();if(T)return T}catch{}throw N}let m=await E();if(!m)throw new Error("idempotent debit settlement did not reach a durable settled state");return{...m,duplicate:l[0]?.rowsAffected===0}}async function Ds(e,t=50){return(await n().execute({sql:"SELECT * FROM ledger WHERE user_id = ? ORDER BY created_at DESC LIMIT ?",args:[e,t]})).rows.map(s=>({id:Number(s.id),user_id:Number(s.user_id),amount_mc:Number(s.amount_mc),operation:String(s.operation),description:s.description!=null?String(s.description):null,stripe_pi:s.stripe_pi!=null?String(s.stripe_pi):null,created_at:String(s.created_at)}))}async function ks(e,t,r){let s=n(),i=r.refund.map(()=>"?").join(", "),a=r.grant.map(()=>"?").join(", "),u=r.purchase.map(()=>"?").join(", "),c=await s.execute({sql:`SELECT
|
|
1256
1323
|
COALESCE(SUM(CASE WHEN amount_mc < 0 AND operation NOT IN (${i}) THEN -amount_mc ELSE 0 END), 0) AS spent_mc,
|
|
1257
1324
|
COALESCE(SUM(CASE WHEN amount_mc > 0 AND operation IN (${i}) THEN amount_mc ELSE 0 END), 0) AS refunded_mc,
|
|
1258
1325
|
COALESCE(SUM(CASE WHEN amount_mc > 0 AND operation IN (${a}) THEN amount_mc ELSE 0 END), 0) AS granted_mc,
|
|
@@ -1262,7 +1329,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1262
1329
|
FROM ledger
|
|
1263
1330
|
WHERE user_id = ? AND created_at >= ? AND amount_mc < 0 AND operation NOT IN (${i})
|
|
1264
1331
|
GROUP BY operation
|
|
1265
|
-
ORDER BY mc DESC, operation ASC`,args:[e,t,...r.refund]}),_=c.rows[0];return{spent_mc:Number(_?.spent_mc??0),refunded_mc:Number(_?.refunded_mc??0),granted_mc:Number(_?.granted_mc??0),purchased_mc:Number(_?.purchased_mc??0),net_mc:Number(_?.net_mc??0),by_operation:o.rows.map(d=>({operation:String(d.operation),mc:Number(d.mc),count:Number(d.count)}))}}async function
|
|
1332
|
+
ORDER BY mc DESC, operation ASC`,args:[e,t,...r.refund]}),_=c.rows[0];return{spent_mc:Number(_?.spent_mc??0),refunded_mc:Number(_?.refunded_mc??0),granted_mc:Number(_?.granted_mc??0),purchased_mc:Number(_?.purchased_mc??0),net_mc:Number(_?.net_mc??0),by_operation:o.rows.map(d=>({operation:String(d.operation),mc:Number(d.mc),count:Number(d.count)}))}}async function vs(e){return(await n().execute({sql:"SELECT 1 FROM ledger WHERE stripe_pi = ? LIMIT 1",args:[e]})).rows.length>0}async function fe(e,t){let r=n();for(let i=0;i<8;i+=1){let u=(await r.execute({sql:`SELECT
|
|
1266
1333
|
u.balance_mc AS cached_balance_mc,
|
|
1267
1334
|
COUNT(l.id) AS lot_count,
|
|
1268
1335
|
COALESCE(SUM(CASE
|
|
@@ -1272,4 +1339,4 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as I,rando
|
|
|
1272
1339
|
FROM users u
|
|
1273
1340
|
LEFT JOIN credit_lots l ON l.user_id = u.id
|
|
1274
1341
|
WHERE u.id = ?
|
|
1275
|
-
GROUP BY u.id, u.balance_mc`,args:[e]})).rows[0];if(!u)return 0;if(Number(u.lot_count??0)===0&&(await
|
|
1342
|
+
GROUP BY u.id, u.balance_mc`,args:[e]})).rows[0];if(!u)return 0;if(Number(u.lot_count??0)===0&&(await R(Number(e)),(await r.execute({sql:"SELECT 1 FROM credit_lots WHERE user_id = ? LIMIT 1",args:[e]})).rows.length>0))continue;let c=Number(u.cached_balance_mc??0),o=Number(u.projected_balance_mc??0);if(c===o||(await r.execute({sql:"UPDATE users SET balance_mc = ? WHERE id = ? AND balance_mc = ?",args:[o,e,c]})).rowsAffected===1)return o}let s=await r.execute({sql:"SELECT balance_mc FROM users WHERE id = ? LIMIT 1",args:[e]});return Number(s.rows[0]?.balance_mc??0)}var Xs=p.object({id:p.string(),user_id:p.number(),status:p.string().default("pending"),client_domain:p.string(),session_path:p.string(),request:p.string(),result:p.string().nullable(),error:p.string().nullable(),created_at:p.string(),updated_at:p.string()}),Ms=p.object({id:p.number(),job_id:p.string(),phase:p.string(),completed_at:p.string(),output_summary:p.string()});async function Fs(e){return(await n().execute({sql:"SELECT id, subject, sent_at, opened_at FROM inbox_messages WHERE user_id = ? AND deleted_at IS NULL ORDER BY sent_at DESC, id DESC",args:[e]})).rows.map(r=>({id:String(r.id),subject:String(r.subject),sent_at:String(r.sent_at),opened_at:r.opened_at!=null?String(r.opened_at):null}))}async function Ps(e,t){let s=(await n().execute({sql:"SELECT id, subject, body_md, source, sent_at, opened_at FROM inbox_messages WHERE id = ? AND user_id = ? AND deleted_at IS NULL",args:[t,e]})).rows[0];if(s)return{id:String(s.id),subject:String(s.subject),body_md:String(s.body_md),source:String(s.source),sent_at:String(s.sent_at),opened_at:s.opened_at!=null?String(s.opened_at):null}}async function Hs(e,t){let r=n();await r.execute({sql:"UPDATE inbox_messages SET opened_at = datetime('now') WHERE id = ? AND user_id = ? AND deleted_at IS NULL AND opened_at IS NULL",args:[t,e]});let i=(await r.execute({sql:"SELECT opened_at FROM inbox_messages WHERE id = ? AND user_id = ? AND deleted_at IS NULL",args:[t,e]})).rows[0];return i&&i.opened_at!=null?String(i.opened_at):null}async function Ws(e,t){return(await n().execute({sql:"UPDATE inbox_messages SET deleted_at = datetime('now') WHERE id = ? AND user_id = ? AND deleted_at IS NULL",args:[t,e]})).rowsAffected>0}async function qs(e,t,r,s="operator"){let i=g();return await n().execute({sql:"INSERT INTO inbox_messages (id, user_id, subject, body_md, source) VALUES (?, ?, ?, ?, ?)",args:[i,e,t,r,s]}),i}async function js(){return(await n().execute("SELECT id FROM users WHERE active = 1")).rows.map(t=>Number(t.id))}export{dt as a,xe as b,ye as c,w as d,ne as e,W as f,Fe as g,Pe as h,ae as i,Q as j,Z as k,ee as l,te as m,re as n,se as o,D as p,I as q,de as r,Lt as s,n as t,St as u,Rt as v,At as w,wt as x,ft as y,Ot as z,ht as A,xt as B,Ve as C,yt as D,It as E,Ct as F,Ut as G,Dt as H,kt as I,vt as J,Xt as K,Mt as L,Ft as M,me as N,ge as O,Pt as P,Ht as Q,Wt as R,qt as S,jt as T,Bt as U,Gt as V,Yt as W,$t as X,Jt as Y,Kt as Z,Vt as _,zt as $,Qt as aa,Zt as ba,er as ca,tr as da,ze as ea,rr as fa,sr as ga,nr as ha,ir as ia,ar as ja,or as ka,ur as la,cr as ma,_r as na,G as oa,dr as pa,lr as qa,Er as ra,Tr as sa,pr as ta,mr as ua,gr as va,Nr as wa,br as xa,B as ya,Lr as za,Sr as Aa,Rr as Ba,Ar as Ca,wr as Da,fr as Ea,tt as Fa,rt as Ga,Or as Ha,hr as Ia,xr as Ja,yr as Ka,Ir as La,Cr as Ma,Ur as Na,Dr as Oa,we as Pa,kr as Qa,vr as Ra,Xr as Sa,Mr as Ta,Fr as Ua,Pr as Va,Hr as Wa,Wr as Xa,qr as Ya,jr as Za,Br as _a,Gr as $a,Yr as ab,$r as bb,Jr as cb,Kr as db,Vr as eb,zr as fb,Qr as gb,Zr as hb,es as ib,ts as jb,rs as kb,ss as lb,ns as mb,is as nb,as as ob,os as pb,us as qb,cs as rb,_s as sb,ds as tb,ls as ub,Es as vb,Ts as wb,it as xb,ps as yb,ms as zb,gs as Ab,ot as Bb,Ns as Cb,bs as Db,Ls as Eb,Ss as Fb,Rs as Gb,As as Hb,ws as Ib,C as Jb,fs as Kb,Os as Lb,hs as Mb,xs as Nb,ys as Ob,Is as Pb,Cs as Qb,ut as Rb,Us as Sb,Ds as Tb,ks as Ub,vs as Vb,fe as Wb,Xs as Xb,Ms as Yb,Fs as Zb,Ps as _b,Hs as $b,Ws as ac,qs as bc,js as cc};
|