mcp-scraper 0.90.3 → 0.90.5

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -1
  3. package/dist/{analytics-repository-UX6VU22H.js → analytics-repository-WNJESD4A.js} +1 -1
  4. package/dist/bin/api-server.js +1 -1
  5. package/dist/bin/mcp-scraper-cli.js +1 -1
  6. package/dist/bin/mcp-scraper-core.js +1 -1
  7. package/dist/bin/mcp-scraper-install.js +1 -1
  8. package/dist/bin/mcp-stdio-server.js +1 -1
  9. package/dist/bin/paa-harvest.js +1 -1
  10. package/dist/{chunk-HR2A2WTL.js → chunk-4OTWTGKC.js} +1 -1
  11. package/dist/{chunk-DKQZNSYM.js → chunk-56UT5M5Y.js} +4 -4
  12. package/dist/{chunk-DWXPUPZQ.js → chunk-5JCPVCBT.js} +1 -1
  13. package/dist/{chunk-HJ7OGU2J.js → chunk-5RTZPHIY.js} +1 -1
  14. package/dist/{chunk-7AC66V3T.js → chunk-AAJG5OHF.js} +1 -1
  15. package/dist/chunk-ARKQYLKU.js +1 -0
  16. package/dist/{chunk-JSNFZPPB.js → chunk-BVSK6YHX.js} +1 -1
  17. package/dist/{chunk-LZTDANNZ.js → chunk-COIA4RW4.js} +1 -1
  18. package/dist/{chunk-3R5QLQT3.js → chunk-IRWULJS5.js} +1 -1
  19. package/dist/{chunk-7BEWBRMT.js → chunk-KKHTMYCD.js} +198 -87
  20. package/dist/{chunk-WTOKMWDS.js → chunk-NC32JCZT.js} +1 -1
  21. package/dist/{chunk-2FHJFKM5.js → chunk-PNDXAOZD.js} +1 -1
  22. package/dist/{chunk-2GRE4BAO.js → chunk-Q5SUDDSQ.js} +1 -1
  23. package/dist/{chunk-PBGOIEEC.js → chunk-W4QBJ7WW.js} +1 -1
  24. package/dist/chunk-X4YCWF4B.js +48 -0
  25. package/dist/{chunk-ZMLCK45S.js → chunk-XSYLDTMI.js} +1 -1
  26. package/dist/{chunk-JVU2THSY.js → chunk-XXK5PLRB.js} +1 -1
  27. package/dist/{chunk-GW6ITK76.js → chunk-ZJOD3YKH.js} +8 -8
  28. package/dist/{db-UKQ74OVT.js → db-XN7YPDGC.js} +1 -1
  29. package/dist/{extract-bundle-7BI2K26D.js → extract-bundle-MQM3P7VS.js} +1 -1
  30. package/dist/{gmail-service-Y2UZX3YW.js → gmail-service-DTUP6EWC.js} +1 -1
  31. package/dist/index.cjs +46 -46
  32. package/dist/index.js +1 -1
  33. package/dist/{lead-list-enrichment-repository-GPDHJVM3.js → lead-list-enrichment-repository-AIMOP7YM.js} +1 -1
  34. package/dist/{location-data-repository-MXUNVDHW.js → location-data-repository-25D3GHXE.js} +1 -1
  35. package/dist/{server-NQCH7HJQ.js → server-NTIME7TQ.js} +591 -588
  36. package/dist/{site-extract-repository-T23S2T7L.js → site-extract-repository-IZT3NTWY.js} +1 -1
  37. package/dist/{stripe-event-worker-HVCB6SF3.js → stripe-event-worker-5QNWGHVK.js} +1 -1
  38. package/dist/worker-Z27YG7TE.js +1 -0
  39. package/package.json +1 -1
  40. package/dist/chunk-PHBU6X5B.js +0 -1
  41. package/dist/chunk-TLF42CG7.js +0 -1
  42. package/dist/worker-KFILERH3.js +0 -1
@@ -1,17 +1,17 @@
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((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 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 (
1
+ import{createClient as Be}from"@libsql/client/http";import{createHash as U,randomBytes as P,randomUUID as N,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.",Ie=["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"],ye=["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 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"||!ie.has(r.error_code))return null;let n=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)&&(n.message=i)}return n}catch{return null}}var ie=new Set(Ie),Ce=new Set(ye),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,n]of Object.entries(e)){if(Object.keys(t).length>=De)break;if(Ue.has(r))if(typeof n=="string"){if((r==="upgrade_url"||r==="topup_url")&&!Xe(n))continue;let i=ae(n).slice(0,ke);i&&(t[r]=i)}else(typeof n=="number"&&Number.isFinite(n)||typeof n=="boolean"||n===null)&&(t[r]=n)}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,n=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}:{},...n?{charge_status:n}:{},...a?{details:a}:{}}}function ae(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 Q=class extends Error{constructor(r){super(`CAPTCHA detected. ${r}`);this.instructions=r}instructions;name="CaptchaError"},Z=class extends Error{constructor(r,n){super(r);this.cause=n}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"},ne=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"],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"},L="strftime('%Y-%m-%dT%H:%M:%fZ','now')";async function x(e,t,r=!1){try{await e.execute(t)}catch(n){let i=n.code;if(!r||i!=="SQL_PARSE_ERROR")throw n}}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),
5
5
  authority_epoch INTEGER NOT NULL CHECK (authority_epoch > 0),
6
6
  authority_state TEXT NOT NULL CHECK (authority_state IN ('ready','authoritative','retired')),
7
- updated_at TEXT NOT NULL DEFAULT (${b})
7
+ updated_at TEXT NOT NULL DEFAULT (${L})
8
8
  ) STRICT`,`CREATE TABLE IF NOT EXISTS oauth_clients (
9
9
  client_id TEXT PRIMARY KEY,
10
10
  client_name TEXT NOT NULL,
11
11
  client_type TEXT NOT NULL CHECK (client_type = 'public'),
12
12
  token_endpoint_auth_method TEXT NOT NULL CHECK (token_endpoint_auth_method = 'none'),
13
13
  status TEXT NOT NULL CHECK (status IN ('active','disabled','expired')),
14
- created_at TEXT NOT NULL DEFAULT (${b}),
14
+ created_at TEXT NOT NULL DEFAULT (${L}),
15
15
  last_used_at TEXT,
16
16
  expires_at TEXT
17
17
  ) STRICT`,`CREATE TABLE IF NOT EXISTS oauth_client_redirect_uris (
@@ -29,7 +29,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
29
29
  user_id TEXT NOT NULL,
30
30
  scope TEXT NOT NULL,
31
31
  resource TEXT,
32
- issued_at TEXT NOT NULL DEFAULT (${b}),
32
+ issued_at TEXT NOT NULL DEFAULT (${L}),
33
33
  expires_at TEXT NOT NULL
34
34
  ) STRICT`,`CREATE TABLE IF NOT EXISTS oauth_code_exchanges (
35
35
  code_digest BLOB PRIMARY KEY,
@@ -44,7 +44,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
44
44
  sealed_nonce BLOB NOT NULL,
45
45
  sealed_tag BLOB NOT NULL,
46
46
  replay_key_id TEXT NOT NULL,
47
- completed_at TEXT NOT NULL DEFAULT (${b}),
47
+ completed_at TEXT NOT NULL DEFAULT (${L}),
48
48
  replay_expires_at TEXT NOT NULL
49
49
  ) STRICT`,`CREATE TABLE IF NOT EXISTS oauth_refresh_families (
50
50
  family_id TEXT PRIMARY KEY,
@@ -55,7 +55,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
55
55
  resource TEXT,
56
56
  status TEXT NOT NULL CHECK (status IN ('active','revoked','compromised','expired')),
57
57
  current_generation INTEGER NOT NULL CHECK (current_generation > 0),
58
- created_at TEXT NOT NULL DEFAULT (${b}),
58
+ created_at TEXT NOT NULL DEFAULT (${L}),
59
59
  expires_at TEXT NOT NULL,
60
60
  revoked_at TEXT,
61
61
  compromised_at TEXT,
@@ -70,7 +70,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
70
70
  lookup_key_id TEXT NOT NULL,
71
71
  token_prefix TEXT NOT NULL,
72
72
  predecessor_generation INTEGER,
73
- issued_at TEXT NOT NULL DEFAULT (${b}),
73
+ issued_at TEXT NOT NULL DEFAULT (${L}),
74
74
  expires_at TEXT NOT NULL,
75
75
  used_at TEXT,
76
76
  revoked_at TEXT,
@@ -85,7 +85,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
85
85
  sealed_nonce BLOB NOT NULL,
86
86
  sealed_tag BLOB NOT NULL,
87
87
  replay_key_id TEXT NOT NULL,
88
- rotated_at TEXT NOT NULL DEFAULT (${b}),
88
+ rotated_at TEXT NOT NULL DEFAULT (${L}),
89
89
  replay_expires_at TEXT NOT NULL,
90
90
  PRIMARY KEY (family_id, predecessor_generation),
91
91
  UNIQUE (family_id, successor_generation),
@@ -95,7 +95,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
95
95
  family_id TEXT NOT NULL,
96
96
  event_type TEXT NOT NULL CHECK (event_type IN ('reuse','binding_mismatch','manual_revoke','expiry')),
97
97
  reason_code TEXT NOT NULL,
98
- occurred_at TEXT NOT NULL DEFAULT (${b}),
98
+ occurred_at TEXT NOT NULL DEFAULT (${L}),
99
99
  retain_until TEXT NOT NULL
100
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)
@@ -106,10 +106,10 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
106
106
  window_seconds INTEGER NOT NULL CHECK (window_seconds BETWEEN 1 AND 604800),
107
107
  count INTEGER NOT NULL CHECK (count >= 1),
108
108
  expires_at INTEGER NOT NULL CHECK (expires_at = window_start + window_seconds),
109
- updated_at TEXT NOT NULL DEFAULT (${b}),
109
+ updated_at TEXT NOT NULL DEFAULT (${L}),
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)`],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(`
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 n=(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=n?.rows[0]?.schema_version==null?void 0:Number(n.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=${L} 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 _e(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 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 (${h.map(()=>"?").join(",")})`,args:[...h]}),n=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=[],_=o=>o.replace(/\bIF\s+NOT\s+EXISTS\b/gi,"").replace(/\s+/g," ").trim().toLowerCase();for(let o of f){if(!n.has(o))continue;let d=(await e.execute(`PRAGMA table_info('${o}')`)).rows.map(g=>String(g.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(g=>_(g).startsWith(`create table ${o} `));(!m||_(l)!==_(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(g=>g.name==null?null:String(g.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(g=>_(g).startsWith(`create index ${o} `));(!m||_(l)!==_(m))&&u.push(`${o}:definition`)}return{ok:f.every(o=>n.has(o))&&h.every(o=>i.has(o))&&Number(a.rows[0]?.foreign_keys??0)===1&&u.length===0,missingTables:f.filter(o=>!n.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",Ke=process.env.TURSO_AUTH_TOKEN,X=null,y="2026-09-22.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","operation_attempts","operation_billing_links","operation_runs","page_snapshots","password_reset_tokens","rate_limits","request_events","provider_reconciliation_runs","provider_usage_receipts","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","operation_attempts_provider_status","operation_attempts_run_number","operation_billing_links_run","operation_runs_idempotency_scope","operation_runs_status_started","operation_runs_tool_started","operation_runs_user_started","page_snapshots_user_checked_at","prt_user_id","request_events_created_at","request_events_user_created_at","provider_reconciliation_runs_provider_started","provider_usage_receipts_attempt","provider_usage_receipts_pending","provider_usage_receipts_provider_source","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"],$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","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($e).map(([n,i])=>`(SELECT COUNT(*) FROM pragma_table_info('${n}') 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 bt(e=s()){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(n){let i=n instanceof Error?n.message.toLowerCase():String(n).toLowerCase();if(!i.includes("no such table")||!i.includes("schema_migrations"))throw n}let r=t?await M(e):!1;return{coreSchemaVersion:y,migrationApplied:t,schemaReady:r}}async function Je(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 U,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:[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(`
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 Je(e),await e.execute({sql:"INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)",args:[de]}))}function s(){return X||(X=Be({url:Ye,authToken:Ke})),X}function St(e){X=e}async function Rt(e=s()){if(process.env.OAUTH_MAINTENANCE_MODE!=="true")throw new Error("Secured main OAuth schema migration requires OAUTH_MAINTENANCE_MODE=true");await _e(e)}async function At(e=s()){return ce(e)}async function wt(e={}){let t=s(),r;try{r=await t.execute({sql:"SELECT 1 AS applied FROM schema_migrations WHERE version = ? LIMIT 1",args:[y]})}catch(n){let i=n instanceof Error?n.message.toLowerCase():String(n).toLowerCase();if(!i.includes("no such table")||!i.includes("schema_migrations"))throw n;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 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(`
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:[y]});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,
@@ -218,7 +218,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
218
218
  completed_at TEXT,
219
219
  UNIQUE(job_id, attempt_number)
220
220
  )
221
- `),await t.execute("CREATE INDEX IF NOT EXISTS harvest_attempts_job_id ON harvest_attempts(job_id)"),await t.execute("CREATE INDEX IF NOT EXISTS harvest_attempts_user_created_at ON harvest_attempts(user_id, created_at DESC)");try{await t.execute("ALTER TABLE harvest_attempts ADD COLUMN debug_json TEXT")}catch{}for(let s of["browser_provider TEXT","provider_session_id TEXT","provider_session_observed_at TEXT","provider_lookup_status TEXT","provider_status TEXT","provider_error_code TEXT","provider_error_message TEXT","provider_reason_source TEXT","provider_duration_ms INTEGER","provider_bandwidth_bytes INTEGER","provider_captcha INTEGER","provider_checked_at TEXT","provider_detail_json TEXT","provider_disconnect_observed INTEGER","provider_disconnect_message TEXT"])try{await t.execute(`ALTER TABLE harvest_attempts ADD COLUMN ${s}`)}catch{}await t.execute("CREATE INDEX IF NOT EXISTS harvest_attempts_provider_lookup ON harvest_attempts(browser_provider, provider_lookup_status, provider_checked_at)");try{await t.execute("ALTER TABLE users ADD COLUMN password_hash TEXT")}catch{}try{await t.execute("ALTER TABLE users ADD COLUMN key_active INTEGER NOT NULL DEFAULT 1")}catch{}await t.execute(`
221
+ `),await t.execute("CREATE INDEX IF NOT EXISTS harvest_attempts_job_id ON harvest_attempts(job_id)"),await t.execute("CREATE INDEX IF NOT EXISTS harvest_attempts_user_created_at ON harvest_attempts(user_id, created_at DESC)");try{await t.execute("ALTER TABLE harvest_attempts ADD COLUMN debug_json TEXT")}catch{}for(let n of["browser_provider TEXT","provider_session_id TEXT","provider_session_observed_at TEXT","provider_lookup_status TEXT","provider_status TEXT","provider_error_code TEXT","provider_error_message TEXT","provider_reason_source TEXT","provider_duration_ms INTEGER","provider_bandwidth_bytes INTEGER","provider_captcha INTEGER","provider_checked_at TEXT","provider_detail_json TEXT","provider_disconnect_observed INTEGER","provider_disconnect_message TEXT"])try{await t.execute(`ALTER TABLE harvest_attempts ADD COLUMN ${n}`)}catch{}await t.execute("CREATE INDEX IF NOT EXISTS harvest_attempts_provider_lookup ON harvest_attempts(browser_provider, provider_lookup_status, provider_checked_at)");try{await t.execute("ALTER TABLE users ADD COLUMN password_hash TEXT")}catch{}try{await t.execute("ALTER TABLE users ADD COLUMN key_active INTEGER NOT NULL DEFAULT 1")}catch{}await t.execute(`
222
222
  CREATE TABLE IF NOT EXISTS kpo_jobs (
223
223
  id TEXT PRIMARY KEY,
224
224
  user_id INTEGER NOT NULL REFERENCES users(id),
@@ -444,6 +444,117 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
444
444
  applied_at TEXT
445
445
  )
446
446
  `),await t.execute("CREATE INDEX IF NOT EXISTS billing_credits_user_status ON billing_credits(user_id, status)"),await t.execute(`
447
+ CREATE TABLE IF NOT EXISTS operation_runs (
448
+ id TEXT PRIMARY KEY,
449
+ user_id INTEGER REFERENCES users(id),
450
+ owner_scope_hash TEXT NOT NULL,
451
+ tool TEXT NOT NULL,
452
+ idempotency_scope_hash TEXT,
453
+ request_fingerprint TEXT,
454
+ job_id TEXT,
455
+ request_id TEXT,
456
+ deployment_commit TEXT,
457
+ normalized_flags_json TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(normalized_flags_json)),
458
+ status TEXT NOT NULL DEFAULT 'running'
459
+ CHECK (status IN ('running', 'succeeded', 'failed', 'cancelled', 'timed_out', 'interrupted', 'unknown')),
460
+ failure_class TEXT,
461
+ started_at TEXT NOT NULL,
462
+ ended_at TEXT,
463
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
464
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
465
+ CHECK ((idempotency_scope_hash IS NULL AND request_fingerprint IS NULL)
466
+ OR (idempotency_scope_hash IS NOT NULL AND request_fingerprint IS NOT NULL)),
467
+ CHECK ((status = 'running' AND ended_at IS NULL) OR (status <> 'running' AND ended_at IS NOT NULL))
468
+ )
469
+ `),await t.execute("CREATE UNIQUE INDEX IF NOT EXISTS operation_runs_idempotency_scope ON operation_runs(idempotency_scope_hash) WHERE idempotency_scope_hash IS NOT NULL"),await t.execute("CREATE INDEX IF NOT EXISTS operation_runs_user_started ON operation_runs(user_id, started_at DESC)"),await t.execute("CREATE INDEX IF NOT EXISTS operation_runs_tool_started ON operation_runs(tool, started_at DESC)"),await t.execute("CREATE INDEX IF NOT EXISTS operation_runs_status_started ON operation_runs(status, started_at)"),await t.execute(`
470
+ CREATE TABLE IF NOT EXISTS operation_attempts (
471
+ id TEXT PRIMARY KEY,
472
+ run_id TEXT NOT NULL REFERENCES operation_runs(id) ON DELETE CASCADE,
473
+ parent_attempt_id TEXT,
474
+ attempt_number INTEGER NOT NULL CHECK (attempt_number > 0),
475
+ edge_kind TEXT CHECK (edge_kind IN ('next_phase', 'parallel_child', 'same_method_retry', 'provider_fallback', 'durable_resume', 'reconciliation')),
476
+ retry_kind TEXT CHECK (retry_kind IN ('same_method', 'provider_fallback', 'durable_resume', 'reconciliation')),
477
+ retry_reason TEXT,
478
+ retry_owner TEXT,
479
+ method TEXT NOT NULL,
480
+ provider TEXT,
481
+ normalized_flags_json TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(normalized_flags_json)),
482
+ status TEXT NOT NULL DEFAULT 'running'
483
+ CHECK (status IN ('running', 'succeeded', 'failed', 'cancelled', 'timed_out', 'interrupted', 'unknown')),
484
+ error_code TEXT,
485
+ error_message TEXT,
486
+ started_at TEXT NOT NULL,
487
+ ended_at TEXT,
488
+ duration_ms INTEGER CHECK (duration_ms IS NULL OR duration_ms >= 0),
489
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
490
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
491
+ UNIQUE (id, run_id),
492
+ FOREIGN KEY (parent_attempt_id, run_id) REFERENCES operation_attempts(id, run_id) ON DELETE RESTRICT,
493
+ CHECK ((attempt_number = 1 AND parent_attempt_id IS NULL AND edge_kind IS NULL AND retry_kind IS NULL)
494
+ OR (attempt_number > 1 AND parent_attempt_id IS NOT NULL AND edge_kind IS NOT NULL)),
495
+ CHECK (retry_kind IS NULL OR edge_kind IN ('same_method_retry', 'provider_fallback', 'durable_resume', 'reconciliation')),
496
+ CHECK ((status = 'running' AND ended_at IS NULL AND duration_ms IS NULL)
497
+ OR (status <> 'running' AND ended_at IS NOT NULL AND duration_ms IS NOT NULL))
498
+ )
499
+ `),await t.execute("CREATE UNIQUE INDEX IF NOT EXISTS operation_attempts_run_number ON operation_attempts(run_id, attempt_number)"),await t.execute("CREATE INDEX IF NOT EXISTS operation_attempts_provider_status ON operation_attempts(provider, status, started_at)"),await t.execute(`
500
+ CREATE TABLE IF NOT EXISTS provider_usage_receipts (
501
+ id TEXT PRIMARY KEY,
502
+ attempt_id TEXT NOT NULL REFERENCES operation_attempts(id) ON DELETE CASCADE,
503
+ provider TEXT NOT NULL,
504
+ account_scope_hash TEXT NOT NULL,
505
+ method TEXT NOT NULL,
506
+ provider_source_key TEXT,
507
+ provider_source_key_hash TEXT,
508
+ cost_state TEXT NOT NULL DEFAULT 'pending'
509
+ CHECK (cost_state IN ('pending', 'estimated', 'actual', 'unavailable')),
510
+ units REAL CHECK (units IS NULL OR units >= 0),
511
+ unit_type TEXT,
512
+ amount_usd_nanos INTEGER CHECK (amount_usd_nanos IS NULL OR amount_usd_nanos >= 0),
513
+ currency TEXT NOT NULL DEFAULT 'USD',
514
+ rate_source TEXT,
515
+ zero_cost_reason TEXT,
516
+ provider_status TEXT,
517
+ provider_duration_ms INTEGER CHECK (provider_duration_ms IS NULL OR provider_duration_ms >= 0),
518
+ provider_captcha INTEGER CHECK (provider_captcha IS NULL OR provider_captcha IN (0, 1)),
519
+ error_code TEXT,
520
+ error_message TEXT,
521
+ checked_at TEXT,
522
+ finalized_at TEXT,
523
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
524
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
525
+ CHECK (provider_source_key IS NULL OR provider_source_key_hash IS NOT NULL),
526
+ CHECK (cost_state <> 'pending' OR (amount_usd_nanos IS NULL AND finalized_at IS NULL)),
527
+ CHECK (cost_state <> 'actual' OR (amount_usd_nanos IS NOT NULL AND finalized_at IS NOT NULL
528
+ AND (amount_usd_nanos > 0 OR zero_cost_reason IS NOT NULL))),
529
+ CHECK (cost_state NOT IN ('estimated', 'unavailable') OR finalized_at IS NOT NULL)
530
+ )
531
+ `),await t.execute("CREATE INDEX IF NOT EXISTS provider_usage_receipts_attempt ON provider_usage_receipts(attempt_id, created_at)"),await t.execute("CREATE INDEX IF NOT EXISTS provider_usage_receipts_pending ON provider_usage_receipts(cost_state, checked_at, created_at) WHERE cost_state = 'pending'"),await t.execute("CREATE UNIQUE INDEX IF NOT EXISTS provider_usage_receipts_provider_source ON provider_usage_receipts(provider, account_scope_hash, method, provider_source_key_hash) WHERE provider_source_key_hash IS NOT NULL"),await t.execute(`
532
+ CREATE TABLE IF NOT EXISTS provider_reconciliation_runs (
533
+ id TEXT PRIMARY KEY,
534
+ provider TEXT NOT NULL,
535
+ status TEXT NOT NULL DEFAULT 'running' CHECK (status IN ('running', 'completed', 'failed')),
536
+ checked_count INTEGER NOT NULL DEFAULT 0 CHECK (checked_count >= 0),
537
+ completed_count INTEGER NOT NULL DEFAULT 0 CHECK (completed_count >= 0),
538
+ pending_count INTEGER NOT NULL DEFAULT 0 CHECK (pending_count >= 0),
539
+ unavailable_count INTEGER NOT NULL DEFAULT 0 CHECK (unavailable_count >= 0),
540
+ failed_count INTEGER NOT NULL DEFAULT 0 CHECK (failed_count >= 0),
541
+ error_code TEXT,
542
+ started_at TEXT NOT NULL,
543
+ completed_at TEXT,
544
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
545
+ CHECK ((status = 'running' AND completed_at IS NULL) OR (status <> 'running' AND completed_at IS NOT NULL))
546
+ )
547
+ `),await t.execute("CREATE INDEX IF NOT EXISTS provider_reconciliation_runs_provider_started ON provider_reconciliation_runs(provider, started_at DESC)"),await t.execute(`
548
+ CREATE TABLE IF NOT EXISTS operation_billing_links (
549
+ run_id TEXT NOT NULL REFERENCES operation_runs(id) ON DELETE CASCADE,
550
+ billing_table TEXT NOT NULL CHECK (billing_table IN ('billing_authorizations', 'billing_events', 'billing_debits', 'billing_credits', 'ledger')),
551
+ billing_key TEXT NOT NULL,
552
+ relation TEXT NOT NULL CHECK (relation IN ('hold', 'settlement', 'debit', 'refund', 'refund_pending')),
553
+ amount_mc INTEGER CHECK (amount_mc IS NULL OR amount_mc >= 0),
554
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
555
+ PRIMARY KEY (run_id, billing_table, billing_key, relation)
556
+ )
557
+ `),await t.execute("CREATE INDEX IF NOT EXISTS operation_billing_links_run ON operation_billing_links(run_id, created_at)"),await t.execute(`
447
558
  CREATE TABLE IF NOT EXISTS admin_credit_adjustments (
448
559
  reference TEXT PRIMARY KEY,
449
560
  user_id INTEGER NOT NULL REFERENCES users(id),
@@ -656,7 +767,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
656
767
  processed_at TEXT NOT NULL DEFAULT (datetime('now')),
657
768
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
658
769
  )
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(`
770
+ `);for(let n 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 ${n}`)}catch{}await t.execute(`
660
771
  UPDATE stripe_events
661
772
  SET updated_at = COALESCE(updated_at, processed_at),
662
773
  received_at = COALESCE(received_at, processed_at, updated_at, datetime('now')),
@@ -706,7 +817,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
706
817
  revoked INTEGER NOT NULL DEFAULT 0,
707
818
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
708
819
  )
709
- `),await t.execute("CREATE INDEX IF NOT EXISTS oauth_tokens_identity ON oauth_tokens(identity)");for(let s of["replaced_by TEXT","rotated_at TEXT"])try{await t.execute(`ALTER TABLE oauth_tokens ADD COLUMN ${s}`)}catch{}await t.execute(`
820
+ `),await t.execute("CREATE INDEX IF NOT EXISTS oauth_tokens_identity ON oauth_tokens(identity)");for(let n of["replaced_by TEXT","rotated_at TEXT"])try{await t.execute(`ALTER TABLE oauth_tokens ADD COLUMN ${n}`)}catch{}await t.execute(`
710
821
  CREATE TABLE IF NOT EXISTS page_snapshots (
711
822
  user_id INTEGER NOT NULL REFERENCES users(id),
712
823
  url TEXT NOT NULL,
@@ -750,7 +861,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
750
861
  updated_at TEXT NOT NULL DEFAULT (datetime('now')),
751
862
  UNIQUE(event_slug, email)
752
863
  )
753
- `);for(let s of["field_notes_email_id TEXT","reminder_48h_email_id TEXT","reminder_24h_email_id TEXT","reminder_1h_email_id TEXT"])try{await t.execute(`ALTER TABLE workshop_registrations ADD COLUMN ${s}`)}catch{}if(await t.execute(`
864
+ `);for(let n of["field_notes_email_id TEXT","reminder_48h_email_id TEXT","reminder_24h_email_id TEXT","reminder_1h_email_id TEXT"])try{await t.execute(`ALTER TABLE workshop_registrations ADD COLUMN ${n}`)}catch{}if(await t.execute(`
754
865
  CREATE INDEX IF NOT EXISTS workshop_registrations_event_status
755
866
  ON workshop_registrations(event_slug, status, registered_at)
756
867
  `),await t.execute(`
@@ -780,20 +891,20 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
780
891
  `),await t.execute(`
781
892
  CREATE UNIQUE INDEX IF NOT EXISTS serp_identities_user_name
782
893
  ON serp_identities(user_id, name)
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
894
+ `),!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:[y]})}async function Ot(e,t,r){await s().execute({sql:"INSERT INTO oauth_clients (client_id, redirect_uris, name) VALUES (?, ?, ?)",args:[e,JSON.stringify(t),r]})}async function ft(e){let r=(await s().execute({sql:"SELECT * FROM oauth_clients WHERE client_id = ?",args:[e]})).rows[0];if(!r)return;let n=[];try{let i=JSON.parse(String(r.redirect_uris));Array.isArray(i)&&(n=i.filter(a=>typeof a=="string"))}catch{n=[]}return{client_id:String(r.client_id),redirect_uris:n,name:r.name!=null?String(r.name):null,created_at:String(r.created_at)}}async function ht(e){await s().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=s(),n=(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]}),!!n)return{code:String(n.code),client_id:String(n.client_id),redirect_uri:String(n.redirect_uri),code_challenge:String(n.code_challenge),identity:String(n.identity),scope:String(n.scope),resource:n.resource!=null?String(n.resource):null,expires_at:String(n.expires_at)}}async function ze(e){await s().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 It(e){let r=(await s().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 yt(e){await s().execute({sql:"UPDATE oauth_tokens SET revoked = 1 WHERE refresh_token = ?",args:[e]})}async function Ct(e,t){await ze(t),await s().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 s().execute({sql:`INSERT OR IGNORE INTO stripe_events
784
895
  (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
896
+ 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))),n=await s().execute({sql:`SELECT event_id
786
897
  FROM stripe_events
787
898
  WHERE (status IN ('pending', 'retryable') AND COALESCE(next_attempt_at, received_at) <= datetime('now'))
788
899
  OR (status = 'processing' AND claimed_at <= datetime('now', '-' || ? || ' seconds'))
789
900
  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
901
+ LIMIT ?`,args:[t,r]}),i=[];for(let a of n.rows){let u=String(a.event_id),_=N();if((await s().execute({sql:`UPDATE stripe_events
791
902
  SET status = 'processing', attempt_count = attempt_count + 1,
792
903
  claim_token = ?, claimed_at = datetime('now'), last_error = NULL,
793
904
  last_error_code = NULL, updated_at = datetime('now')
794
905
  WHERE event_id = ?
795
906
  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
907
+ OR (status = 'processing' AND claimed_at <= datetime('now', '-' || ? || ' seconds')))`,args:[_,u,t]})).rowsAffected!==1)continue;let c=await s().execute({sql:"SELECT event_type, attempt_count FROM stripe_events WHERE event_id = ? LIMIT 1",args:[u]});i.push({eventId:u,eventType:c.rows[0]?.event_type!=null?String(c.rows[0].event_type):null,attemptCount:Number(c.rows[0]?.attempt_count??1),token:_})}return i}async function kt(e,t){return(await s().execute({sql:`UPDATE stripe_events
797
908
  SET status = 'processed',
798
909
  claim_token = NULL,
799
910
  claimed_at = NULL,
@@ -802,7 +913,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
802
913
  last_error = NULL,
803
914
  processed_at = datetime('now'),
804
915
  updated_at = datetime('now')
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
916
+ WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[e,t]})).rowsAffected===1}async function vt(e,t,r,n,i){return(await s().execute({sql:`UPDATE stripe_events
806
917
  SET status = 'retryable',
807
918
  claim_token = NULL,
808
919
  claimed_at = NULL,
@@ -810,10 +921,10 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
810
921
  last_error_code = ?,
811
922
  next_attempt_at = datetime('now', '+' || ? || ' seconds'),
812
923
  updated_at = datetime('now')
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
924
+ WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[r.slice(0,500),n.slice(0,100),Math.max(0,Math.trunc(i)),e,t]})).rowsAffected===1}async function Xt(e,t,r,n){return(await s().execute({sql:`UPDATE stripe_events
814
925
  SET status = 'dead_letter', claim_token = NULL, claimed_at = NULL,
815
926
  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(`
927
+ WHERE event_id = ? AND status = 'processing' AND claim_token = ?`,args:[r.slice(0,500),n.slice(0,100),e,t]})).rowsAffected===1}async function Mt(){let t=(await s().execute(`
817
928
  SELECT
818
929
  SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending,
819
930
  SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END) AS processing,
@@ -821,21 +932,21 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
821
932
  SUM(CASE WHEN status = 'dead_letter' THEN 1 ELSE 0 END) AS dead_letter,
822
933
  MIN(CASE WHEN status IN ('pending', 'retryable') THEN COALESCE(next_attempt_at, received_at) END) AS oldest_due_at
823
934
  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:`
935
+ `)).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 s().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 Ne(e){let t=P(16).toString("hex"),r=pe(e,t,64);return`${t}:${r.toString("hex")}`}function Pt(e,t){let[r,n]=t.split(":"),i=Buffer.from(n,"hex"),a=pe(e,r,64);return Ge(i,a)}function b(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 s().execute({sql:"SELECT * FROM users WHERE email = ? AND active = 1",args:[e]});return t.rows[0]?b(t.rows[0]):void 0}async function Wt(e){let t=await s().execute({sql:"SELECT * FROM users WHERE api_key = ? AND active = 1 AND key_active = 1",args:[e]});return t.rows[0]?b(t.rows[0]):void 0}async function qt(e){let t=await s().execute({sql:"SELECT * FROM users WHERE id = ? AND active = 1",args:[e]});return t.rows[0]?b(t.rows[0]):void 0}async function jt(e){let r=(await s().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 s().execute({sql:"UPDATE users SET memory_key = ?, memory_identity = ? WHERE id = ?",args:[t,r,e]})}async function Gt(e,t){await s().execute({sql:"UPDATE users SET password_hash = ? WHERE id = ?",args:[Ne(t),e]})}async function Yt(e){let t=s(),[r,n,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(n.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 Kt(e,t,r,n){let i=s(),a=me(),u=r??P(6).toString("hex"),_=Ne(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,_,n??null]})).lastInsertRowid,email:e,name:t,api_key:a,password:u}}async function $t(e,t,r,n){let i=Math.floor(Date.now()/1e3),a=Math.floor(i/n)*n,u=U("sha256").update(t).digest("hex"),o=await s().execute({sql:`
825
936
  INSERT INTO rate_limits (scope, key_hash, window_start, count)
826
937
  VALUES (?, ?, ?, 1)
827
938
  ON CONFLICT(scope, key_hash, window_start)
828
939
  DO UPDATE SET count = count + 1, updated_at = datetime('now')
829
940
  RETURNING count
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,\u006b\u0065\u0072\u006e\u0065\u006c_session_id:e.\u006b\u0065\u0072\u006e\u0065\u006c_session_id!=null?String(e.\u006b\u0065\u0072\u006e\u0065\u006c_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),\u006b\u0065\u0072\u006e\u0065\u006c_delete_started:Number(e.\u006b\u0065\u0072\u006e\u0065\u006c_delete_started??0)===1,\u006b\u0065\u0072\u006e\u0065\u006c_delete_succeeded:y(e.\u006b\u0065\u0072\u006e\u0065\u006c_delete_succeeded),\u006b\u0065\u0072\u006e\u0065\u006c_delete_error:e.\u006b\u0065\u0072\u006e\u0065\u006c_delete_error!=null?String(e.\u006b\u0065\u0072\u006e\u0065\u006c_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)
941
+ `,args:[e,u,a]}),c=Number(o.rows[0]?.count);if(!Number.isSafeInteger(c)||c<1)throw new Error("Rate-limit bucket mutation did not return a valid count");return{allowed:c<=r,count:c,remaining:Math.max(0,r-c),resetSeconds:Math.max(1,a+n-i)}}async function Jt(e){let t=P(32).toString("hex"),r=U("sha256").update(t).digest("hex"),n=new Date(Date.now()+3600*1e3).toISOString();return await s().execute({sql:"INSERT INTO password_reset_tokens (token, user_id, expires_at) VALUES (?, ?, ?)",args:[r,e,n]}),t}async function zt(e){let t=s(),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 Vt(e){let t=me();return await s().execute({sql:"UPDATE users SET api_key = ?, key_active = 1 WHERE id = ?",args:[t,e]}),t}async function Qt(e){await s().execute({sql:"UPDATE users SET key_active = 0 WHERE id = ?",args:[e]})}async function Zt(){return(await s().execute("SELECT id, email, name, created_at, active FROM users ORDER BY created_at DESC")).rows.map(t=>b({...t,api_key:"",key_active:1}))}async function er(e){await s().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 I(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 ge(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,\u006b\u0065\u0072\u006e\u0065\u006c_session_id:e.\u006b\u0065\u0072\u006e\u0065\u006c_session_id!=null?String(e.\u006b\u0065\u0072\u006e\u0065\u006c_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:I(e.will_retry),\u006b\u0065\u0072\u006e\u0065\u006c_delete_started:Number(e.\u006b\u0065\u0072\u006e\u0065\u006c_delete_started??0)===1,\u006b\u0065\u0072\u006e\u0065\u006c_delete_succeeded:I(e.\u006b\u0065\u0072\u006e\u0065\u006c_delete_succeeded),\u006b\u0065\u0072\u006e\u0065\u006c_delete_error:e.\u006b\u0065\u0072\u006e\u0065\u006c_delete_error!=null?String(e.\u006b\u0065\u0072\u006e\u0065\u006c_delete_error):null,browser_close_succeeded:I(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:I(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:I(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 O(e){let{public_error_json:t,...r}=e;return{...r,options:JSON.parse(e.options),result:e.result?JSON.parse(e.result):null,publicError:se(t)}}async function tr(e,t,r,n){let i=N();return await Ve(i,e,t,r,n),i}async function Ve(e,t,r,n,i){if(!/^[a-zA-Z0-9-]{1,100}$/.test(e))throw new Error("job id is invalid");await s().execute({sql:"INSERT INTO jobs (id, user_id, query, options, callback_url) VALUES (?, ?, ?, ?, ?)",args:[e,t,r,JSON.stringify(n),i??null]})}async function rr(e,t,r){let n=N();return await s().execute({sql:"INSERT INTO jobs (id, user_id, query, options, status, started_at) VALUES (?, ?, ?, ?, 'running', datetime('now'))",args:[n,e,t,JSON.stringify(r)]}),n}async function nr(e,t,r,n){let i=await s().execute({sql:`INSERT INTO jobs (id, user_id, query, options, status, started_at)
831
942
  VALUES (?, ?, ?, ?, 'running', datetime('now'))
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:`
943
+ ON CONFLICT(id) DO NOTHING`,args:[e,t,r,JSON.stringify(n)]}),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 sr(e){await s().execute({sql:`
833
944
  INSERT INTO harvest_attempts (
834
945
  id, job_id, user_id, attempt_number, max_attempts, query, location, max_questions, status, created_at
835
946
  )
836
947
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'running', ?)
837
948
  ON CONFLICT(job_id, attempt_number) DO NOTHING
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:`
949
+ `,args:[N(),e.jobId,e.userId,e.attemptNumber,e.maxAttempts,e.query,e.location,e.maxQuestions,e.startedAt]})}async function ir(e){return(await s().execute({sql:`
839
950
  UPDATE harvest_attempts SET
840
951
  browser_provider = ?,
841
952
  provider_session_id = ?,
@@ -845,7 +956,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
845
956
  ELSE 'pending'
846
957
  END
847
958
  WHERE job_id = ? AND attempt_number = ? AND status = 'running'
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:`
959
+ `,args:[e.browserProvider,e.providerSessionId,e.observedAt,e.jobId,e.attemptNumber]})).rowsAffected===1}async function ar(e,t,r=new Date().toISOString()){return(await s().execute({sql:`
849
960
  UPDATE harvest_attempts SET
850
961
  status = 'finished',
851
962
  outcome = COALESCE(outcome, 'timeout'),
@@ -858,7 +969,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
858
969
  provider_reason_source = COALESCE(provider_reason_source, 'client_runtime'),
859
970
  completed_at = COALESCE(completed_at, ?)
860
971
  WHERE job_id = ? AND status = 'running'
861
- `,args:[r,t?1:0,r,e]})).rowsAffected}async function or(e){await n().execute({sql:`
972
+ `,args:[r,t?1:0,r,e]})).rowsAffected}async function or(e){await s().execute({sql:`
862
973
  UPDATE harvest_attempts SET
863
974
  status = 'finished',
864
975
  outcome = ?,
@@ -901,7 +1012,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
901
1012
  debug_json = ?,
902
1013
  completed_at = ?
903
1014
  WHERE job_id = ? AND attempt_number = ?
904
- `,args:[e.outcome,e.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,e.questionCount,e.durationMs,e.error,e.willRetry?1:0,e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted?1:0,e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded==null?null:e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded?1:0,e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteError,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:`
1015
+ `,args:[e.outcome,e.\u006b\u0065\u0072\u006e\u0065\u006cSessionId,e.questionCount,e.durationMs,e.error,e.willRetry?1:0,e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteStarted?1:0,e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded==null?null:e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteSucceeded?1:0,e.\u006b\u0065\u0072\u006e\u0065\u006cDeleteError,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:Le(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 Le(e,t=4096){let r=JSON.stringify(e);return r.length<=t?r:JSON.stringify({truncated:!0})}async function ur(e){return(await s().execute({sql:`
905
1016
  UPDATE harvest_attempts SET
906
1017
  provider_lookup_status = ?,
907
1018
  provider_status = ?,
@@ -919,24 +1030,24 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
919
1030
  AND browser_provider = '\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api'
920
1031
  AND provider_session_id = ?
921
1032
  AND COALESCE(provider_lookup_status, '') <> 'complete'
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:`
1033
+ `,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:Le(e.detail),e.attemptId,e.jobId,e.userId,e.providerSessionId]})).rowsAffected===1}async function _r(e=25){let t=Math.max(1,Math.min(100,Math.trunc(e)));return(await s().execute({sql:`
923
1034
  SELECT * FROM harvest_attempts
924
1035
  WHERE browser_provider = '\u0062\u0072\u0069\u0067\u0068\u0074_\u0064\u0061\u0074\u0061_browser_api'
925
1036
  AND provider_session_id IS NOT NULL
926
1037
  AND provider_lookup_status IN ('pending', 'temporary_error')
927
1038
  ORDER BY COALESCE(provider_checked_at, created_at) ASC
928
1039
  LIMIT ?
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:`
1040
+ `,args:[t]})).rows.map(n=>ge(n))}async function cr(e,t){return(t==null?await s().execute({sql:"SELECT * FROM harvest_attempts WHERE job_id = ? ORDER BY attempt_number ASC",args:[e]}):await s().execute({sql:`
930
1041
  SELECT ha.*
931
1042
  FROM harvest_attempts ha
932
1043
  INNER JOIN jobs j ON j.id = ha.job_id
933
1044
  WHERE ha.job_id = ? AND j.user_id = ?
934
1045
  ORDER BY ha.attempt_number ASC
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
1046
+ `,args:[e,t]})).rows.map(n=>ge(n))}async function G(e,t){let r=s(),n=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 n.rows[0]?O(S(n.rows[0])):void 0}async function dr(e,t,r){await s().execute({sql:`UPDATE jobs
936
1047
  SET status = 'running', started_at = COALESCE(started_at, datetime('now'))
937
1048
  WHERE id = ? AND status = 'pending'
938
1049
  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
1050
+ AND json_extract(options, '$.jobKind') = ?`,args:[e,t,r]});let n=await G(e);if(!(!n||n.options.executionOwner!==t||n.options.jobKind!==r))return n}async function lr(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await s().execute({sql:`SELECT * FROM jobs
940
1051
  WHERE status = 'pending'
941
1052
  AND json_extract(options, '$.executionOwner') = 'inngest'
942
1053
  AND json_extract(options, '$.jobKind') = 'extract_url'
@@ -944,14 +1055,14 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
944
1055
  AND created_at <= datetime('now', '-30 seconds')
945
1056
  AND datetime(COALESCE(json_extract(options, '$.extractUrlLastDispatchAt'), '1970-01-01')) <= datetime('now', '-30 seconds')
946
1057
  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
1058
+ LIMIT ?`,args:[t]})).rows.map(n=>O(S(n)))}async function Er(e,t){return(await s().execute({sql:`UPDATE jobs
948
1059
  SET options = json_set(options,
949
1060
  '$.extractUrlDispatchAttempts', COALESCE(json_extract(options, '$.extractUrlDispatchAttempts'), 0) + 1,
950
1061
  '$.extractUrlLastDispatchAt', ?,
951
1062
  '$.extractUrlLastDispatchError', ?)
952
1063
  WHERE id = ? AND status = 'pending'
953
1064
  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:`
1065
+ AND json_extract(options, '$.jobKind') = 'extract_url'`,args:[new Date().toISOString(),t??null,e]})).rowsAffected===1}async function Tr(e){return(await s().execute({sql:"SELECT * FROM jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50",args:[e]})).rows.map(r=>O(S(r)))}async function pr(e,t){let n=(await s().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 n?{contentHash:String(n.content_hash),content:String(n.content),title:n.title==null?null:String(n.title),contentBytes:Number(n.content_bytes),truncated:Number(n.truncated)===1,checkedAt:String(n.checked_at)}:null}async function mr(e,t,r){await s().execute({sql:`
955
1066
  INSERT INTO page_snapshots (user_id, url, content_hash, content, title, content_bytes, truncated, checked_at)
956
1067
  VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
957
1068
  ON CONFLICT(user_id, url) DO UPDATE SET
@@ -961,56 +1072,56 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
961
1072
  content_bytes = excluded.content_bytes,
962
1073
  truncated = excluded.truncated,
963
1074
  checked_at = excluded.checked_at
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:`
1075
+ `,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 Nr(e){let t=N();return await s().execute({sql:`
965
1076
  INSERT INTO request_events (id, user_id, source, status, query, location, result_count, result, error)
966
1077
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
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:`
1078
+ `,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 gr(e,t=100){return(await s().execute({sql:`
968
1079
  SELECT id, user_id, source, status, query, location, result_count, NULL AS result, error, created_at
969
1080
  FROM request_events
970
1081
  WHERE user_id = ?
971
1082
  ORDER BY created_at DESC
972
1083
  LIMIT ?
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:`
1084
+ `,args:[e,t]})).rows.map(n=>et(n))}function be(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:be(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 K(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:be(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 Lr(e){let t=N();await s().execute({sql:`
974
1085
  INSERT INTO workflow_schedules (
975
1086
  id, user_id, workflow_id, name, input_json, cadence, timezone, webhook_url, next_run_at
976
1087
  )
977
1088
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
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:`
1089
+ `,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 s().execute({sql:"SELECT * FROM workflow_schedules WHERE id = ? AND status != ? LIMIT 1",args:[e,"deleted"]}):await s().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 br(e){return(await s().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 s().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 s().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 s().execute({sql:`
979
1090
  SELECT * FROM workflow_schedules
980
1091
  WHERE status = 'active' AND next_run_at IS NOT NULL AND next_run_at <= ?
981
1092
  ORDER BY next_run_at ASC
982
1093
  LIMIT ?
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:`
1094
+ `,args:[e,t]})).rows.map(n=>Y(n))}async function wr(e,t,r){await s().execute({sql:"UPDATE workflow_schedules SET last_run_at = ?, next_run_at = ?, updated_at = datetime('now') WHERE id = ?",args:[t,r,e]})}async function Or(e){let t=e.id??N(),r=[t,e.userId,e.scheduleId??null,e.workflowId,JSON.stringify(e.workflowInput),e.idempotencyKey??null,e.webhookUrl??null,e.totalSteps??null];try{await s().execute({sql:`
984
1095
  INSERT INTO workflow_runs (id, user_id, schedule_id, workflow_id, input_json, idempotency_key, webhook_url, total_steps)
985
1096
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
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:`
1097
+ `,args:r})}catch(i){if(e.idempotencyKey){let a=await rt(e.idempotencyKey);if(a)return a}throw i}let n=await tt(t,e.userId);if(!n)throw new Error("Failed to create workflow run");return n}async function tt(e,t){let r=t==null?await s().execute({sql:"SELECT * FROM workflow_runs WHERE id = ? LIMIT 1",args:[e]}):await s().execute({sql:"SELECT * FROM workflow_runs WHERE id = ? AND user_id = ? LIMIT 1",args:[e,t]});return r.rows[0]?K(r.rows[0]):null}async function rt(e){let t=await s().execute({sql:"SELECT * FROM workflow_runs WHERE idempotency_key = ? LIMIT 1",args:[e]});return t.rows[0]?K(t.rows[0]):null}async function fr(e,t=50){return(await s().execute({sql:"SELECT * FROM workflow_runs WHERE user_id = ? ORDER BY queued_at DESC LIMIT ?",args:[e,t]})).rows.map(n=>K(n))}async function hr(e){await s().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 s().execute({sql:"UPDATE workflow_runs SET status = ?, manifest_json = ?, completed_at = datetime('now') WHERE id = ?",args:[t,JSON.stringify(r),e]})}async function Ir(e,t,r){await s().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 nt(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 s().execute({sql:`
987
1098
  INSERT INTO workflow_artifacts (id, run_id, user_id, kind, label, path, content_type, bytes, rows_count, content)
988
1099
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
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:`
1100
+ `,args:[N(),e,t,r.kind,r.label,r.path,nt(r.kind),r.bytes??null,r.rows??null,r.content??null]})}async function yr(e,t,r){await s().execute({sql:"DELETE FROM workflow_artifacts WHERE run_id = ? AND user_id = ?",args:[e,t]});for(let n of r)await Ae(e,t,n);return we(e,t)}async function Cr(e,t,r){for(let n of r)await Ae(e,t,n);return we(e,t)}async function Ur(e,t){let n=(t==null?await s().execute({sql:"SELECT step_index, total_steps, step_state_json, step_log_json FROM workflow_runs WHERE id = ? LIMIT 1",args:[e]}):await s().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 n?{stepIndex:n.step_index!=null?Number(n.step_index):0,totalSteps:n.total_steps!=null?Number(n.total_steps):null,state:n.step_state_json!=null?F(n.step_state_json):null,stepLog:Se(n.step_log_json)}:null}async function Dr(e,t){let r=[...t.appendLog,t.logEntry];await s().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 s().execute({sql:"SELECT * FROM workflow_artifacts WHERE run_id = ? AND user_id = ? ORDER BY created_at ASC",args:[e,t]})).rows.map(n=>Re(n))}async function kr(e,t){let r=await s().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 s().execute({sql:`
990
1101
  INSERT INTO workflow_webhook_deliveries (
991
1102
  id, run_id, schedule_id, user_id, webhook_url, status, attempts, last_error, delivered_at
992
1103
  )
993
1104
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
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(`
1105
+ `,args:[N(),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 s().execute("SELECT COUNT(*) as n FROM users WHERE active = 1");return Number(e.rows[0]?.n??0)}async function Mr(e){let t=await s().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=s(),t=await e.execute(`
995
1106
  SELECT * FROM jobs
996
1107
  WHERE status = 'pending'
997
1108
  AND COALESCE(json_extract(options, '$.executionOwner'), 'cron') NOT IN ('direct', 'inngest')
998
1109
  ORDER BY created_at
999
1110
  LIMIT 1
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
1111
+ `),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 $=45e3;async function Pr(e){let t=s(),r=await G(e);if(!r||r.options.executionOwner!=="direct"||r.options.serpOnly===!0)return;let n=Math.max(0,Number(r.options.paaRecoveryCount??0));if(r.status!=="running"){if(r.status==="pending"){let i=N(),a=new Date().toISOString(),u=new Date(Date.now()+$).toISOString();return(await t.execute({sql:`UPDATE jobs
1001
1112
  SET status = 'running', started_at = datetime('now'), error = NULL,
1002
1113
  options = json_set(options,
1003
1114
  '$.paaLeaseToken', ?,
1004
1115
  '$.paaLeaseExpiresAt', ?,
1005
1116
  '$.paaLastDispatchAt', ?)
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,
1117
+ 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:n}}return{job:r,leaseToken:null,recoveryCount:n}}}async function Hr(e,t){return(await s().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 n=new Date(Date.now()+$).toISOString();return(await s().execute({sql:`UPDATE jobs SET result = ?, options = json_set(options, '$.paaLeaseExpiresAt', ?)
1118
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[JSON.stringify(r),n,e,t]})).rowsAffected===1}async function qr(e,t){let r=new Date(Date.now()+$).toISOString();return(await s().execute({sql:`UPDATE jobs SET options = json_set(options, '$.paaLeaseExpiresAt', ?)
1119
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[r,e,t]})).rowsAffected===1}async function jr(e,t,r){return(await s().execute({sql:`UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL,
1009
1120
  completed_at = datetime('now'),
1010
1121
  options = json_set(options, '$.paaLeaseExpiresAt', NULL)
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'),
1122
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[JSON.stringify(r),e,t]})).rowsAffected===1}async function Br(e,t,r,n){return(await s().execute({sql:`UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now'),
1012
1123
  options = json_set(options, '$.paaLeaseExpiresAt', NULL)
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,
1124
+ WHERE id = ? AND status = 'running' AND json_extract(options, '$.paaLeaseToken') = ?`,args:[r,w(n),e,t]})).rowsAffected===1}async function Gr(e,t){let r=new Date().toISOString();return(await s().execute({sql:`UPDATE jobs SET status = 'pending', started_at = NULL,
1014
1125
  result = CASE WHEN json_valid(result) THEN json_set(result,
1015
1126
  '$.progress.lifecycle.discoveryStatus', 'interrupted',
1016
1127
  '$.progress.lifecycle.completionReason', 'The previous worker lease expired; the same job is recovering automatically.',
@@ -1026,28 +1137,28 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1026
1137
  datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
1027
1138
  OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
1028
1139
  )
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')
1140
+ 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 s().execute({sql:`UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL, completed_at = datetime('now')
1030
1141
  WHERE id = ? AND status = 'running'
1031
1142
  AND (
1032
1143
  datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
1033
1144
  OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
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')
1145
+ )`,args:[JSON.stringify(t),e]})).rowsAffected===1}async function Kr(e,t,r){return(await s().execute({sql:`UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now')
1035
1146
  WHERE id = ? AND status = 'running'
1036
1147
  AND (
1037
1148
  datetime(json_extract(options, '$.paaLeaseExpiresAt')) <= datetime('now')
1038
1149
  OR (json_extract(options, '$.paaLeaseExpiresAt') IS NULL AND started_at <= datetime('now', '-15 minutes'))
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
1150
+ )`,args:[t,w(r),e]})).rowsAffected===1}async function $r(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await s().execute({sql:`SELECT * FROM jobs
1040
1151
  WHERE status IN ('done', 'failed', 'cancelled')
1041
1152
  AND json_extract(options, '$.executionOwner') IN ('direct', 'inngest')
1042
1153
  AND json_extract(options, '$.billingDebitKey') IS NOT NULL
1043
1154
  AND json_extract(options, '$.billingSettledAt') IS NULL
1044
1155
  ORDER BY completed_at DESC
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
1156
+ LIMIT ?`,args:[t]})).rows.map(n=>O(S(n)))}async function Jr(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await s().execute({sql:`SELECT * FROM jobs
1046
1157
  WHERE status = 'running'
1047
1158
  AND started_at <= datetime('now', '-15 minutes')
1048
1159
  AND json_extract(options, '$.executionOwner') IN ('direct', 'inngest')
1049
1160
  ORDER BY started_at
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
1161
+ LIMIT ?`,args:[t]})).rows.map(n=>O(S(n)))}async function zr(e=25){let t=Math.max(1,Math.min(100,Math.floor(e)));return(await s().execute({sql:`SELECT * FROM jobs
1051
1162
  WHERE json_extract(options, '$.executionOwner') = 'direct'
1052
1163
  AND json_extract(options, '$.serpOnly') IS NOT 1
1053
1164
  AND (
@@ -1060,11 +1171,11 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1060
1171
  AND datetime(COALESCE(json_extract(options, '$.paaLastDispatchAt'), '1970-01-01')) <= datetime('now', '-30 seconds'))
1061
1172
  )
1062
1173
  ORDER BY COALESCE(started_at, created_at)
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
1174
+ LIMIT ?`,args:[t]})).rows.map(n=>O(S(n)))}async function Vr(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 s().execute({sql:`UPDATE jobs
1064
1175
  SET options = json_set(options, '$.billingSettledAt', ?, '$.billedMc', ?)
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)
1176
+ WHERE id = ?`,args:[r,t,e]})).rowsAffected===1}async function Qr(e,t){await s().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 s().execute({sql:`UPDATE jobs SET status = 'done', result = ?, error = NULL, public_error_json = NULL, completed_at = datetime('now')
1177
+ WHERE id = ? AND status = 'running'`,args:[JSON.stringify(t),e]})).rowsAffected===1}async function en(e,t,r){await s().execute({sql:"UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now') WHERE id = ?",args:[t,w(r),e]})}async function tn(e,t,r){return(await s().execute({sql:`UPDATE jobs SET status = 'failed', error = ?, public_error_json = ?, completed_at = datetime('now')
1178
+ WHERE id = ? AND status = 'running'`,args:[t,w(r),e]})).rowsAffected===1}async function rn(e,t,r){await s().execute({sql:"UPDATE jobs SET status = 'cancelled', error = ?, public_error_json = ?, completed_at = datetime('now') WHERE id = ?",args:[t,w(r),e]})}function J(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 st(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 nn(e,t,r,n,i,a){await s().execute({sql:"INSERT INTO kpo_jobs (id, user_id, status, entity_name, entity_type, url, request) VALUES (?, ?, 'pending', ?, ?, ?, ?)",args:[e,t,r,n,a??null,JSON.stringify(i)]})}async function sn(){let t=await s().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]?J(t.rows[0]):null}async function an(e){let t=await s().execute({sql:"SELECT * FROM kpo_jobs WHERE id = ?",args:[e]});return t.rows[0]?J(t.rows[0]):null}async function on(e,t){await s().execute({sql:"UPDATE kpo_jobs SET status = ?, updated_at = datetime('now') WHERE id = ?",args:[t,e]})}async function un(e,t){await s().execute({sql:"UPDATE kpo_jobs SET status = 'done', result = ?, updated_at = datetime('now') WHERE id = ?",args:[JSON.stringify(t),e]})}async function _n(e,t){await s().execute({sql:"UPDATE kpo_jobs SET status = 'failed', error = ?, updated_at = datetime('now') WHERE id = ?",args:[t,e]})}async function cn(e,t,r){await s().execute({sql:"INSERT INTO kpo_phase_log (job_id, phase, output) VALUES (?, ?, ?)",args:[e,t,JSON.stringify(r)]})}async function dn(e){return(await s().execute({sql:"SELECT * FROM kpo_phase_log WHERE job_id = ? ORDER BY created_at ASC",args:[e]})).rows.map(r=>st(r))}async function ln(e){return(e!=null?await s().execute({sql:"SELECT * FROM kpo_jobs WHERE user_id = ? ORDER BY created_at DESC LIMIT 50",args:[e]}):await s().execute("SELECT * FROM kpo_jobs ORDER BY created_at DESC LIMIT 50")).rows.map(r=>J(r))}async function En(e){let t=await s().execute({sql:"SELECT * FROM users WHERE stripe_customer_id = ? AND active = 1",args:[e]});return t.rows[0]?b(t.rows[0]):void 0}async function Tn(e,t){await s().execute({sql:"UPDATE users SET stripe_customer_id = ? WHERE id = ?",args:[t,e]})}async function pn(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 s().execute({sql:"UPDATE users SET concurrency_pack_quantity = ?, extra_concurrency_slots = ? WHERE id = ?",args:[t,t*2,e]})}async function mn(e,t){await s().execute({sql:"UPDATE users SET concurrency_stripe_sub_id = ? WHERE id = ?",args:[t,e]})}async function Nn(e,t,r,n){await s().execute({sql:"UPDATE users SET subscription_tier = ?, subscription_concurrency = ?, subscription_id = ? WHERE id = ?",args:[t,Math.max(0,Math.round(r)),n,e]})}async function gn(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=s(),r=e.neverExpires?"9999-12-31 23:59:59":null,n=await t.batch([{sql:`INSERT OR IGNORE INTO ledger (user_id, amount_mc, operation, description, stripe_pi)
1068
1179
  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
1180
  SELECT ?, ?, ?, 'subscription', ?, COALESCE(?, datetime('now', ?)), ?
1070
1181
  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
@@ -1077,7 +1188,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1077
1188
  WHERE stripe_pi = ? AND user_id = ? AND amount_mc = ? AND operation = 'subscription'
1078
1189
  )`,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
1190
  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
1191
+ 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:n[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 s().execute({sql:"SELECT * FROM connected_account_billing WHERE user_id = ? LIMIT 1",args:[e]})).rows[0];return r?at(r):null}async function Ln(e){let t=Math.max(0,Math.round(e.quantity));await s().execute({sql:`INSERT INTO connected_account_billing
1081
1192
  (user_id, stripe_subscription_id, stripe_subscription_item_id, price_id, quantity, status, last_error_code, checked_at, synced_at, updated_at)
1082
1193
  VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'), CASE WHEN ? THEN datetime('now') ELSE NULL END, datetime('now'))
1083
1194
  ON CONFLICT(user_id) DO UPDATE SET
@@ -1089,14 +1200,14 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1089
1200
  last_error_code = excluded.last_error_code,
1090
1201
  checked_at = datetime('now'),
1091
1202
  synced_at = CASE WHEN ? THEN datetime('now') ELSE connected_account_billing.synced_at END,
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.*
1203
+ 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 bn(e=60,t=20){let r=`-${Math.max(1,Math.round(e))} minutes`;return(await s().execute({sql:`SELECT u.*
1093
1204
  FROM users u
1094
1205
  LEFT JOIN connected_account_billing b ON b.user_id = u.id
1095
1206
  WHERE u.active = 1
1096
1207
  AND u.subscription_id IS NOT NULL
1097
1208
  AND (b.checked_at IS NULL OR b.checked_at <= datetime('now', ?))
1098
1209
  ORDER BY COALESCE(b.checked_at, u.created_at) ASC
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)
1210
+ LIMIT ?`,args:[r,Math.max(1,Math.min(100,Math.round(t)))]})).rows.map(i=>b(i))}async function Sn(e,t,r){await s().execute({sql:"UPDATE users SET memory_plan = ?, memory_subscription_id = ? WHERE id = ?",args:[t,r,e]})}async function Rn(e){let r=(await s().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 An(e){let r=(await s().execute({sql:"SELECT memory_provisioned FROM users WHERE id = ?",args:[e]})).rows[0];return Number(r?.memory_provisioned??0)===1}async function wn(e,t){await s().execute({sql:"UPDATE users SET memory_provisioned = ? WHERE id = ?",args:[t?1:0,e]})}async function On(e){let t=await s().execute({sql:"SELECT * FROM users WHERE memory_subscription_id = ? AND active = 1",args:[e]});return t.rows[0]?b(t.rows[0]):void 0}var C="+3 months";async function R(e){return(await s().execute({sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, expires_at)
1100
1211
  SELECT ?, legacy.balance_mc, legacy.balance_mc, 'migration', datetime('now', ?)
1101
1212
  FROM (
1102
1213
  SELECT COALESCE(SUM(amount_mc), 0) AS balance_mc
@@ -1110,44 +1221,44 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1110
1221
  )
1111
1222
  AND NOT EXISTS (
1112
1223
  SELECT 1 FROM credit_lots WHERE user_id = ?
1113
- )`,args:[e,C,e,e,D,e]})).rowsAffected}async function fs(){let e=n(),t=await e.execute({sql:`SELECT id
1224
+ )`,args:[e,C,e,e,D,e]})).rowsAffected}async function fn(){let e=s(),t=await e.execute({sql:`SELECT id
1114
1225
  FROM credit_lots
1115
1226
  WHERE remaining_mc > 0
1116
1227
  AND never_expires = 0
1117
1228
  AND expires_at <= datetime('now')
1118
- LIMIT 500`});if(t.rows.length===0)return{expired_lots:0,expired_mc:0};let r=[],s=[];for(let _ of t.rows){let d=Number(_.id),E=g();r.push({token:E,insertResultIndex:s.length}),s.push({sql:`INSERT OR IGNORE INTO credit_lot_expirations (lot_id, user_id, amount_mc, claim_token)
1229
+ LIMIT 500`});if(t.rows.length===0)return{expired_lots:0,expired_mc:0};let r=[],n=[];for(let c of t.rows){let d=Number(c.id),E=N();r.push({token:E,insertResultIndex:n.length}),n.push({sql:`INSERT OR IGNORE INTO credit_lot_expirations (lot_id, user_id, amount_mc, claim_token)
1119
1230
  SELECT id, user_id, remaining_mc, ?
1120
1231
  FROM credit_lots
1121
1232
  WHERE id = ?
1122
1233
  AND remaining_mc > 0
1123
1234
  AND never_expires = 0
1124
- AND expires_at <= datetime('now')`,args:[E,d]}),s.push({sql:`UPDATE credit_lots
1235
+ AND expires_at <= datetime('now')`,args:[E,d]}),n.push({sql:`UPDATE credit_lots
1125
1236
  SET remaining_mc = 0
1126
1237
  WHERE id = ?
1127
1238
  AND EXISTS (
1128
1239
  SELECT 1 FROM credit_lot_expirations
1129
1240
  WHERE lot_id = ? AND claim_token = ?
1130
- )`,args:[d,d,E]}),s.push({sql:`INSERT INTO ledger (user_id, amount_mc, operation, description)
1241
+ )`,args:[d,d,E]}),n.push({sql:`INSERT INTO ledger (user_id, amount_mc, operation, description)
1131
1242
  SELECT user_id, -amount_mc, 'credit_expired', 'credits expired'
1132
1243
  FROM credit_lot_expirations
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
1244
+ WHERE lot_id = ? AND claim_token = ?`,args:[d,E]})}let i=await e.batch(n,"write"),a=r.filter(c=>i[c.insertResultIndex]?.rowsAffected===1).map(c=>c.token);if(a.length===0)return{expired_lots:0,expired_mc:0};let u=a.map(()=>"?").join(", "),_=await e.execute({sql:`SELECT user_id, amount_mc
1134
1245
  FROM credit_lot_expirations
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
1246
+ WHERE claim_token IN (${u})`,args:a}),o=new Set(_.rows.map(c=>Number(c.user_id)));for(let c of o)await Oe(c);return{expired_lots:_.rows.length,expired_mc:_.rows.reduce((c,d)=>c+Number(d.amount_mc),0)}}async function hn(){let e=s(),t=await e.execute({sql:`SELECT DISTINCT u.id AS user_id
1136
1247
  FROM users u
1137
1248
  JOIN ledger l ON l.user_id = u.id
1138
1249
  WHERE l.created_at < ?
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
1250
+ AND NOT EXISTS (SELECT 1 FROM credit_lots WHERE user_id = u.id)`,args:[D]}),r=0,n=0;for(let i of t.rows){let a=Number(i.user_id);if(await R(a)===0)continue;let _=await e.execute({sql:`SELECT amount_mc FROM credit_lots
1140
1251
  WHERE user_id = ? AND source = 'migration'
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)
1252
+ ORDER BY id DESC LIMIT 1`,args:[a]}),o=Number(_.rows[0]?.amount_mc??0);await Oe(a),r+=1,n+=o}return{migrated:r,total_mc:n}}async function xn(e,t,r,n,i,a){let u=s();await R(e);let _=a?.neverExpires;if(_===void 0&&t>0){let E=await u.execute({sql:"SELECT subscription_tier FROM users WHERE id = ? LIMIT 1",args:[e]});_=String(E.rows[0]?.subscription_tier??"").startsWith("sonic")}let o=_?"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,n??null,i]}];t>0&&E.push({sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, stripe_pi, expires_at, never_expires)
1142
1253
  SELECT ?, ?, ?, ?, ?, COALESCE(?, datetime('now', ?)), ?
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)
1254
+ WHERE changes() = 1`,args:[e,t,t,r,i,o,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 c=[];t>0&&c.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,_?1:0]}),c.push({sql:"UPDATE users SET balance_mc = balance_mc + ? WHERE id = ?",args:[t,e]}),c.push({sql:"INSERT INTO ledger (user_id, amount_mc, operation, description, stripe_pi) VALUES (?, ?, ?, ?, ?)",args:[e,t,r,n??null,null]}),await u.batch(c,"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 In(e,t,r,n,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=s();await R(e);let _=a?.neverExpires;if(_===void 0){let m=await u.execute({sql:"SELECT subscription_tier FROM users WHERE id = ? LIMIT 1",args:[e]});_=String(m.rows[0]?.subscription_tier??"").startsWith("sonic")}let o=_?"9999-12-31 23:59:59":null,c=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,n]},{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,n]},{sql:`INSERT INTO credit_lots (user_id, amount_mc, remaining_mc, source, stripe_pi, expires_at, never_expires)
1144
1255
  SELECT user_id, amount_mc, amount_mc, operation, NULL, COALESCE(?, datetime('now', ?)), ?
1145
1256
  FROM billing_credits
1146
- WHERE idempotency_key = ? AND status = 'applying'`,args:[o,C,c?1:0,i]},{sql:`UPDATE users
1257
+ WHERE idempotency_key = ? AND status = 'applying'`,args:[o,C,_?1:0,i]},{sql:`UPDATE users
1147
1258
  SET balance_mc = balance_mc + COALESCE((
1148
1259
  SELECT amount_mc FROM billing_credits WHERE idempotency_key = ? AND status = 'applying'
1149
1260
  ), 0)
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
1261
+ 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)===n)return{ok:!0,balance_mc:await c(),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)!==n)throw new Error("idempotent credit key conflicts with another credit");return{ok:String(l.status)==="applied",balance_mc:await c(),duplicate:d[1]?.rowsAffected===0&&String(l.status)==="applied"}}async function yn(e,t){return(await s().execute({sql:"SELECT 1 FROM ledger WHERE user_id = ? AND operation = ? LIMIT 1",args:[e,t]})).rows.length>0}async function Cn(e,t){return(await s().execute({sql:"INSERT OR IGNORE INTO free_credit_refreshes (user_id, month) VALUES (?, ?)",args:[e,t]})).rowsAffected>0}async function Un(e,t,r,n){let i=await ut(e,t,r,n??"",`debit:${N()}`);return{ok:i.ok,balance_mc:i.balance_mc}}async function ut(e,t,r,n,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=s();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,n]},{sql:"INSERT OR IGNORE INTO billing_debits (idempotency_key, user_id, amount_mc, operation, description, status) VALUES (?, ?, ?, ?, ?, 'claimed')",args:[i,e,t,r,n]},{sql:`UPDATE users
1151
1262
  SET balance_mc = balance_mc - ?
1152
1263
  WHERE id = ?
1153
1264
  AND balance_mc >= ?
@@ -1156,7 +1267,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1156
1267
  WHERE user_id = ?
1157
1268
  AND remaining_mc > 0
1158
1269
  AND (never_expires = 1 OR expires_at > datetime('now'))) >= ?
1159
- AND EXISTS (SELECT 1 FROM billing_debits WHERE idempotency_key = ? AND user_id = ? AND amount_mc = ? AND operation = ? AND description = ? AND status = 'claimed')`,args:[t,e,t,e,t,i,e,t,r,s]},{sql:"UPDATE billing_debits SET status = 'applying' WHERE idempotency_key = ? AND user_id = ? AND amount_mc = ? AND operation = ? AND description = ? AND status = 'claimed' AND changes() = 1",args:[i,e,t,r,s]},{sql:`INSERT OR IGNORE INTO billing_debit_allocations
1270
+ AND EXISTS (SELECT 1 FROM billing_debits WHERE idempotency_key = ? AND user_id = ? AND amount_mc = ? AND operation = ? AND description = ? AND status = 'claimed')`,args:[t,e,t,e,t,i,e,t,r,n]},{sql:"UPDATE billing_debits SET status = 'applying' WHERE idempotency_key = ? AND user_id = ? AND amount_mc = ? AND operation = ? AND description = ? AND status = 'claimed' AND changes() = 1",args:[i,e,t,r,n]},{sql:`INSERT OR IGNORE INTO billing_debit_allocations
1160
1271
  (debit_idempotency_key, lot_id, user_id, amount_mc, expires_at)
1161
1272
  WITH ordered AS MATERIALIZED (
1162
1273
  SELECT id,
@@ -1183,7 +1294,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1183
1294
  WHERE id IN (
1184
1295
  SELECT lot_id FROM billing_debit_allocations WHERE debit_idempotency_key = ?
1185
1296
  )
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,
1297
+ 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)===n){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)!==n)throw new Error("idempotent debit key conflicts with another debit");let c=await a.execute({sql:"SELECT balance_mc FROM users WHERE id = ?",args:[e]});return{ok:String(o.status)==="applied",balance_mc:Number(c.rows[0]?.balance_mc??0),duplicate:u[2]?.rowsAffected===0&&String(o.status)==="applied"}}async function Dn(e,t,r,n,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(!n||!a)throw new Error("idempotent debit settlement operation and source are required");let u=s();await R(e);let _=`debit-settlement:${U("sha256").update(t).digest("hex")}`,o="wallet_hold_settlement",c=N(),d=JSON.stringify({debitIdempotencyKey:t,refundOperation:n,description:i}),E=async()=>{let T=(await u.execute({sql:`SELECT e.user_id,
1187
1298
  e.status,
1188
1299
  e.amount_mc AS final_amount_mc,
1189
1300
  e.billing_class,
@@ -1195,7 +1306,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1195
1306
  WHERE e.idempotency_key = ?
1196
1307
  AND d.user_id = e.user_id
1197
1308
  AND d.status = 'applied'
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 (
1309
+ LIMIT 1`,args:[t,_]})).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 fe=H-A,z=await u.execute({sql:`WITH ordered AS (
1199
1310
  SELECT a.amount_mc,
1200
1311
  a.expires_at,
1201
1312
  COALESCE(SUM(a.amount_mc) OVER (
@@ -1211,9 +1322,9 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1211
1322
  )
1212
1323
  SELECT (SELECT COUNT(*) FROM ordered) AS allocation_count,
1213
1324
  COALESCE(SUM(CASE WHEN expires_at > ? THEN refund_mc ELSE 0 END), 0) AS credited_refund_mc
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
1325
+ FROM refunds`,args:[t,A,String(T.settled_at)]}),V=Number(z.rows[0]?.allocation_count??0)>0?Number(z.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:V,expired_refund_mc:fe-V,duplicate:!0}},l;try{l=await u.batch([{sql:`INSERT OR IGNORE INTO billing_events
1215
1326
  (id, user_id, idempotency_key, billing_class, source_surface, status, amount_mc, metadata)
1216
- VALUES (?, ?, ?, ?, ?, 'settling', ?, ?)`,args:[_,e,c,o,a,r,d]},{sql:`WITH ordered AS (
1327
+ VALUES (?, ?, ?, ?, ?, 'settling', ?, ?)`,args:[c,e,_,o,a,r,d]},{sql:`WITH ordered AS (
1217
1328
  SELECT a.lot_id,
1218
1329
  a.amount_mc,
1219
1330
  a.expires_at,
@@ -1254,14 +1365,14 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1254
1365
  AND d.user_id = e.user_id
1255
1366
  AND d.status = 'applied'
1256
1367
  AND e.amount_mc BETWEEN 0 AND d.amount_mc
1257
- )`,args:[t,r,e,t,c,e,o,a]},{sql:`UPDATE billing_events
1368
+ )`,args:[t,r,e,t,_,e,o,a]},{sql:`UPDATE billing_events
1258
1369
  SET status = 'applying'
1259
1370
  WHERE idempotency_key = ?
1260
1371
  AND user_id = ?
1261
1372
  AND billing_class = ?
1262
1373
  AND source_surface = ?
1263
1374
  AND status = 'settling'
1264
- AND changes() = 1`,args:[c,e,o,a]},{sql:`WITH ordered AS (
1375
+ AND changes() = 1`,args:[_,e,o,a]},{sql:`WITH ordered AS (
1265
1376
  SELECT a.lot_id,
1266
1377
  a.amount_mc,
1267
1378
  a.expires_at,
@@ -1283,7 +1394,7 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1283
1394
  SELECT lot_id FROM refunds
1284
1395
  WHERE refund_mc > 0 AND expires_at > datetime('now')
1285
1396
  )
1286
- AND EXISTS (SELECT 1 FROM billing_events WHERE idempotency_key = ? AND status = 'applying')`,args:[t,r,c]},{sql:`WITH ordered AS (
1397
+ AND EXISTS (SELECT 1 FROM billing_events WHERE idempotency_key = ? AND status = 'applying')`,args:[t,r,_]},{sql:`WITH ordered AS (
1287
1398
  SELECT a.amount_mc,
1288
1399
  a.expires_at,
1289
1400
  COALESCE(SUM(a.amount_mc) OVER (
@@ -1316,20 +1427,20 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1316
1427
  ?,
1317
1428
  ?
1318
1429
  FROM credited
1319
- WHERE refund_mc > 0`,args:[t,r,t,c,s,i]},{sql:`UPDATE billing_events
1430
+ WHERE refund_mc > 0`,args:[t,r,t,_,n,i]},{sql:`UPDATE billing_events
1320
1431
  SET status = 'settled', settled_at = datetime('now')
1321
1432
  WHERE idempotency_key = ?
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
1433
+ AND status = 'applying'`,args:[_]}],"write")}catch(g){try{let T=await E();if(T)return T}catch{}throw g}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 kn(e,t=50){return(await s().execute({sql:"SELECT * FROM ledger WHERE user_id = ? ORDER BY created_at DESC LIMIT ?",args:[e,t]})).rows.map(n=>({id:Number(n.id),user_id:Number(n.user_id),amount_mc:Number(n.amount_mc),operation:String(n.operation),description:n.description!=null?String(n.description):null,stripe_pi:n.stripe_pi!=null?String(n.stripe_pi):null,created_at:String(n.created_at)}))}async function vn(e,t,r){let n=s(),i=r.refund.map(()=>"?").join(", "),a=r.grant.map(()=>"?").join(", "),u=r.purchase.map(()=>"?").join(", "),_=await n.execute({sql:`SELECT
1323
1434
  COALESCE(SUM(CASE WHEN amount_mc < 0 AND operation NOT IN (${i}) THEN -amount_mc ELSE 0 END), 0) AS spent_mc,
1324
1435
  COALESCE(SUM(CASE WHEN amount_mc > 0 AND operation IN (${i}) THEN amount_mc ELSE 0 END), 0) AS refunded_mc,
1325
1436
  COALESCE(SUM(CASE WHEN amount_mc > 0 AND operation IN (${a}) THEN amount_mc ELSE 0 END), 0) AS granted_mc,
1326
1437
  COALESCE(SUM(CASE WHEN amount_mc > 0 AND operation IN (${u}) THEN amount_mc ELSE 0 END), 0) AS purchased_mc,
1327
1438
  COALESCE(SUM(amount_mc), 0) AS net_mc
1328
- FROM ledger WHERE user_id = ? AND created_at >= ?`,args:[...r.refund,...r.refund,...r.grant,...r.purchase,e,t]}),o=await s.execute({sql:`SELECT operation, -SUM(amount_mc) AS mc, COUNT(*) AS count
1439
+ FROM ledger WHERE user_id = ? AND created_at >= ?`,args:[...r.refund,...r.refund,...r.grant,...r.purchase,e,t]}),o=await n.execute({sql:`SELECT operation, -SUM(amount_mc) AS mc, COUNT(*) AS count
1329
1440
  FROM ledger
1330
1441
  WHERE user_id = ? AND created_at >= ? AND amount_mc < 0 AND operation NOT IN (${i})
1331
1442
  GROUP BY operation
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
1443
+ ORDER BY mc DESC, operation ASC`,args:[e,t,...r.refund]}),c=_.rows[0];return{spent_mc:Number(c?.spent_mc??0),refunded_mc:Number(c?.refunded_mc??0),granted_mc:Number(c?.granted_mc??0),purchased_mc:Number(c?.purchased_mc??0),net_mc:Number(c?.net_mc??0),by_operation:o.rows.map(d=>({operation:String(d.operation),mc:Number(d.mc),count:Number(d.count)}))}}async function Xn(e){return(await s().execute({sql:"SELECT 1 FROM ledger WHERE stripe_pi = ? LIMIT 1",args:[e]})).rows.length>0}async function Oe(e,t){let r=s();for(let i=0;i<8;i+=1){let u=(await r.execute({sql:`SELECT
1333
1444
  u.balance_mc AS cached_balance_mc,
1334
1445
  COUNT(l.id) AS lot_count,
1335
1446
  COALESCE(SUM(CASE
@@ -1339,4 +1450,4 @@ import{createClient as Be}from"@libsql/client/http";import{createHash as U,rando
1339
1450
  FROM users u
1340
1451
  LEFT JOIN credit_lots l ON l.user_id = u.id
1341
1452
  WHERE u.id = ?
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};
1453
+ 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 _=Number(u.cached_balance_mc??0),o=Number(u.projected_balance_mc??0);if(_===o||(await r.execute({sql:"UPDATE users SET balance_mc = ? WHERE id = ? AND balance_mc = ?",args:[o,e,_]})).rowsAffected===1)return o}let n=await r.execute({sql:"SELECT balance_mc FROM users WHERE id = ? LIMIT 1",args:[e]});return Number(n.rows[0]?.balance_mc??0)}var Mn=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()}),Fn=p.object({id:p.number(),job_id:p.string(),phase:p.string(),completed_at:p.string(),output_summary:p.string()});async function Pn(e){return(await s().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 Hn(e,t){let n=(await s().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(n)return{id:String(n.id),subject:String(n.subject),body_md:String(n.body_md),source:String(n.source),sent_at:String(n.sent_at),opened_at:n.opened_at!=null?String(n.opened_at):null}}async function Wn(e,t){let r=s();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 qn(e,t){return(await s().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 jn(e,t,r,n="operator"){let i=N();return await s().execute({sql:"INSERT INTO inbox_messages (id, user_id, subject, body_md, source) VALUES (?, ?, ?, ?, ?)",args:[i,e,t,r,n]}),i}async function Bn(){return(await s().execute("SELECT id FROM users WHERE active = 1")).rows.map(t=>Number(t.id))}export{dt as a,xe as b,Ie as c,w as d,se 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,ne as o,D as p,y as q,de as r,bt as s,s as t,St as u,Rt as v,At as w,wt as x,Ot as y,ft as z,ht as A,xt as B,ze as C,It as D,yt 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,Ne 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,Kt as X,$t as Y,Jt as Z,zt as _,Vt as $,Qt as aa,Zt as ba,er as ca,tr as da,Ve as ea,rr as fa,nr as ga,sr as ha,ir as ia,ar as ja,or as ka,ur as la,_r as ma,cr as na,G as oa,dr as pa,lr as qa,Er as ra,Tr as sa,pr as ta,mr as ua,Nr as va,gr as wa,Lr as xa,B as ya,br as za,Sr as Aa,Rr as Ba,Ar as Ca,wr as Da,Or as Ea,tt as Fa,rt as Ga,fr as Ha,hr as Ia,xr as Ja,Ir as Ka,yr 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,Kr as bb,$r as cb,Jr as db,zr as eb,Vr as fb,Qr as gb,Zr as hb,en as ib,tn as jb,rn as kb,nn as lb,sn as mb,an as nb,on as ob,un as pb,_n as qb,cn as rb,dn as sb,ln as tb,En as ub,Tn as vb,pn as wb,it as xb,mn as yb,Nn as zb,gn as Ab,ot as Bb,Ln as Cb,bn as Db,Sn as Eb,Rn as Fb,An as Gb,wn as Hb,On as Ib,C as Jb,fn as Kb,hn as Lb,xn as Mb,In as Nb,yn as Ob,Cn as Pb,Un as Qb,ut as Rb,Dn as Sb,kn as Tb,vn as Ub,Xn as Vb,Oe as Wb,Mn as Xb,Fn as Yb,Pn as Zb,Hn as _b,Wn as $b,qn as ac,jn as bc,Bn as cc};