@smart-cloud/publisher-exporter 1.1.39 → 1.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/content-sync.js +8 -8
- package/dist/crawl.js +6 -6
- package/dist/deploy.js +4 -4
- package/dist/invalidate.js +3 -3
- package/package.json +1 -1
package/dist/deploy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import R from'fs/promises';import mt from'http';import ht from'https';import b from'path';import {S3Client,HeadObjectCommand,GetObjectCommand,DeleteObjectsCommand,ListObjectsV2Command}from'@aws-sdk/client-s3';import {Upload}from'@aws-sdk/lib-storage';import qt,{createHash}from'crypto';import Gt from'fast-glob';import br from'mime-types';import {availableParallelism}from'os';import {Worker}from'worker_threads';function Me(t){let e=t.trim();return e==="."?".":e.replace(/\/$/,"")}function yt(t){let e=String(t??"").trim();if(!e)return "";let r=e;if(/^https?:\/\//i.test(r))try{r=new URL(r).pathname;}catch{return ""}if(r=r.split(/[?#]/,1)[0]?.replace(/\\/g,"/").trim()??"",!r)return "";let i=r.endsWith("/"),n=r.replace(/^\/+/,"").split("/").map(o=>o.replace(/[^A-Za-z0-9._-]/g,"")).filter(o=>o.length>0&&o!=="."&&o!=="..");if(n.length===0)return "";let s=`/${n.join("/")}`;return i&&b.extname(s)===""&&(s+="/"),s==="/"?"":s}function de(t){return !t||typeof t!="object"?{}:Object.fromEntries(Object.entries(t).map(([e,r])=>[e.trim(),String(r??"")]).filter(([e])=>e.length>0))}function wt(t){if(!t||typeof t!="object")return {};let e={};for(let[r,i]of Object.entries(t)){let n=r.trim();if(!n||!i||typeof i!="object")continue;let s=i,o={};if(typeof s.targetOrigin=="string"){let a=Me(s.targetOrigin);a&&(o.targetOrigin=a);}let l=de(s.extraReplacements);if(Object.keys(l).length>0&&(o.extraReplacements=l),s.s3&&typeof s.s3=="object"){let a={},c=s.s3;typeof c.bucket=="string"&&(a.bucket=c.bucket.trim()),typeof c.prefix=="string"&&(a.prefix=c.prefix.trim()),typeof c.region=="string"&&(a.region=c.region.trim()),typeof c.htmlCacheControl=="string"&&(a.htmlCacheControl=c.htmlCacheControl.trim()),typeof c.assetCacheControl=="string"&&(a.assetCacheControl=c.assetCacheControl.trim()),Object.keys(a).length>0&&(o.s3=a);}if(s.cloudFront&&typeof s.cloudFront=="object"){let a={},c=s.cloudFront;typeof c.distributionId=="string"&&(a.distributionId=c.distributionId.trim()),Array.isArray(c.invalidationPaths)&&(a.invalidationPaths=c.invalidationPaths.map(u=>String(u??"").trim()).filter(u=>u.length>0)),Object.keys(a).length>0&&(o.cloudFront=a);}e[n]=o;}return e}function me(t){return t==="PROFESSIONAL"||t==="AGENCY"?t:void 0}function bt(t,e){if(!t||typeof t!="object")return null;let r=t,i=r.command;if(i!=="publish"&&i!=="crawl"&&i!=="deploy"&&i!=="invalidate"&&i!=="retry-timeouts"&&i!=="url"&&i!=="content-sync")return null;let n=Number.parseInt(String(r.intervalMinutes??"0"),10);if(!Number.isFinite(n)||n<1)return null;let s=String(r.id??`${i}-${e+1}`).trim();if(!s)return null;let o=String(r.deploymentProfile??"").trim(),l=String(r.url??"").trim(),a=Array.isArray(r.postTypes)?[...new Set(r.postTypes.map(u=>String(u??"").trim().toLowerCase().replace(/[^a-z0-9_-]/g,"")).filter(Boolean))]:[],c=Array.isArray(r.listingPaths)?[...new Set(r.listingPaths.map(u=>String(u??"").trim()).filter(Boolean))]:[];return i==="content-sync"&&a.length===0?null:{id:s,enabled:r.enabled!==false,command:i,intervalMinutes:n,...i==="publish"||i==="crawl"?{crawlMode:r.crawlMode==="incremental"?"incremental":"full"}:{},...(i==="publish"||i==="deploy"||i==="invalidate"||i==="content-sync")&&o?{deploymentProfile:o}:{},...l?{url:l}:{},...a.length>0?{postTypes:a}:{},...c.length>0?{listingPaths:c}:{},...typeof r.includePostTypeArchives=="boolean"?{includePostTypeArchives:r.includePostTypeArchives}:{},...typeof r.includeTaxonomyArchives=="boolean"?{includeTaxonomyArchives:r.includeTaxonomyArchives}:{},...typeof r.includeAuthorArchives=="boolean"?{includeAuthorArchives:r.includeAuthorArchives}:{},...typeof r.includeDateArchives=="boolean"?{includeDateArchives:r.includeDateArchives}:{},...typeof r.includePostsPage=="boolean"?{includePostsPage:r.includePostsPage}:{},...typeof r.includeSitemapChain=="boolean"?{includeSitemapChain:r.includeSitemapChain}:{}}}function Ae(t){let e=t&&typeof t=="object"?t:{},r=Array.isArray(e.rules)?e.rules.map((i,n)=>bt(i,n)).filter(i=>!!i):[];return {enabled:e.enabled===true,timezone:typeof e.timezone=="string"&&e.timezone.trim()!==""?e.timezone.trim():"UTC",rules:r}}function Pt(t){if(!t||typeof t!="object")return;let e=t,r={};for(let n of ["accountId","siteId"]){let s=e[n];typeof s=="string"&&s.trim()!==""&&(r[n]=s.trim());}let i=Number(e.lastUpdate??0);return Number.isFinite(i)&&i>0&&(r.lastUpdate=Math.floor(i)),e.subscriber===true&&(r.subscriber=true),Object.keys(r).length>0?r:void 0}function he(t){let e=t&&typeof t=="object"?t:{},r=String(e.accountId??"").trim(),i=String(e.siteId??"").trim(),n=e.subscriber===true,s=Pt(e.siteSettings),o={...s??{},...r?{accountId:s?.accountId??r}:{},...i?{siteId:s?.siteId??i}:{},...s?.subscriber===true||n?{subscriber:true}:{}},l={},a=String(e.apiBase??"").trim();a&&(l.apiBase=a);let c=String(e.runtimeToken??e.nonce??"").trim();c&&(l.runtimeToken=c);let u=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();u&&(l.virtualAssetBaseUrl=u),Object.keys(o).length>0&&(l.siteSettings=o);let m=me(e.subscriptionType);return m&&(l.subscriptionType=m),l}function St(t){try{let e=new URL(t);globalThis.location=e;}catch{}}function ke(t){return typeof t=="string"?t:t instanceof URL?t.toString():t.url}function vt(t,e){let r=new Headers(t instanceof Request?t.headers:void 0);if(e?.headers)for(let[i,n]of new Headers(e.headers).entries())r.set(i,n);return r}async function Ie(t,e,r=5){let i=new URL(ke(t)),n=String(e?.method??(t instanceof Request?t.method:"GET")).toUpperCase(),s=i.protocol==="http:"?mt:ht,o=vt(t,e);return await new Promise((l,a)=>{let c=s.request(i,{method:n,headers:Object.fromEntries(o.entries()),...i.protocol==="https:"?{rejectUnauthorized:false}:{}},u=>{let m=[];u.on("data",p=>{m.push(Buffer.isBuffer(p)?p:Buffer.from(p));}),u.on("error",a),u.on("end",()=>{let p=u.statusCode??0,d=u.headers.location;if(r>0&&d&&[301,302,303,307,308].includes(p)){l(Ie(new URL(d,i),{method:p===303?"GET":n},r-1));return}let g=new Headers;for(let[w,C]of Object.entries(u.headers))Array.isArray(C)?g.set(w,C.join(", ")):typeof C=="string"&&g.set(w,C);l(new Response(Buffer.concat(m),{status:p,statusText:u.statusMessage??"",headers:g}));});});c.on("error",a),c.end();})}function Rt(t){let e=he(t.wpsuite),r={...e.siteSettings??{},...e.siteSettings?.subscriber===true||e.subscriptionType==="PROFESSIONAL"||e.subscriptionType==="AGENCY"?{subscriber:true}:{}},i=String(r.accountId??"").trim(),n=String(r.siteId??"").trim(),s=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();if(t.wpsuite={...e.apiBase?{apiBase:e.apiBase}:{},...e.runtimeToken?{runtimeToken:e.runtimeToken}:{},...s?{virtualAssetBaseUrl:s}:{},...Object.keys(r).length>0?{siteSettings:r}:{},...e.subscriptionType?{subscriptionType:e.subscriptionType}:{}},!i||!n||!s)return false;St(t.sourceOrigin);let o=globalThis,a={...o.WpSuite??{},siteSettings:r,uploadUrl:s};return e.apiBase&&(a.apiBase=e.apiBase),o.WpSuite=a,true}async function Dt(t){let e=String(t.wpsuite?.virtualAssetBaseUrl??t.wpsuite?.uploadUrl??"").trim();if(!Rt(t)){let n=t.wpsuite?.siteSettings,s=[String(n?.accountId??"").trim()?"":"accountId",String(n?.siteId??"").trim()?"":"siteId",e?"":"virtualAssetBaseUrl"].filter(Boolean);return {remote:null,diagnostic:{status:"invalid-runtime",virtualAssetBaseUrl:e,subscriptionType:null,error:`Missing WP Suite runtime field(s): ${s.join(", ")}.`,requests:[]}}}let r=globalThis.fetch,i=[];try{typeof r=="function"&&/^https?:\/\//i.test(e)&&(globalThis.fetch=(async(a,c)=>{let u=ke(a);if(u.startsWith(e)){let m=(()=>{try{return new URL(u).pathname}catch{return u}})();try{let p=t.ignoreHttpsErrors&&u.startsWith("https://")?await Ie(a,c):await r(a,c);return i.push({path:m,status:p.status,ok:p.ok,error:null}),p}catch(p){throw i.push({path:m,status:null,ok:!1,error:p instanceof Error?p.message:String(p)}),p}}return r(a,c)}));let{getConfig:n}=await import('@smart-cloud/wpsuite-core'),s=await n("publisher"),o=s&&typeof s=="object"?s:null,l=me(o?.subscriptionType);return {remote:o,diagnostic:{status:o?"loaded":"unavailable",virtualAssetBaseUrl:e,subscriptionType:l??null,error:o?null:"WP Suite publisher config loader returned no configuration.",requests:i}}}catch(n){return {remote:null,diagnostic:{status:"unavailable",virtualAssetBaseUrl:e,subscriptionType:null,error:n instanceof Error?n.message:String(n),requests:i}}}finally{typeof r=="function"&&(globalThis.fetch=r);}}function xt(t,e){let r=wt(e?.deploymentProfiles),i=String(e?.defaultDeploymentProfile??"").trim(),n=r[i]?i:"",s=me(e?.subscriptionType),o=he(t.wpsuite);return {...t,scheduler:Ae(e?.scheduler),deploymentProfiles:r,defaultDeploymentProfile:n,...s?{subscriptionType:s}:{},wpsuite:{...o,...o.siteSettings||s?{siteSettings:{...o.siteSettings??{},...o.siteSettings?.subscriber===true||s==="PROFESSIONAL"||s==="AGENCY"?{subscriber:true}:{}}}:{},...s?{subscriptionType:s}:{}}}}function fe(t,e){let i=String(t||"").replace(/\\/g,"/").trim().replace(/^\/+|\/+$/g,"");if(!i)return e;let n=i.split("/").map(s=>s.trim()).filter(s=>s.length>0&&s!=="."&&s!=="..");return n.length>0?n.join("/"):e}function $t(){let t=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return t.trim()?b.resolve(t):""}function Ee(t,e,r){let i=String(e||"").trim();return i&&b.isAbsolute(i)?b.resolve(i):b.resolve(t,fe(i,r))}async function re(t,e={}){let r=String("").trim()||process.env.PUBLISHER_CONFIG||"publisher.config.json",i=await R.readFile(r,"utf8"),n=JSON.parse(i);n.sourceOrigin=n.sourceOrigin.replace(/\/$/,""),n.targetOrigin=Me(n.targetOrigin),n.ignoreHttpsErrors??=false,n.outputDir=String(n.outputDir||"export").trim()||"export",n.urlRewriteMode||=n.targetOrigin==="."?"relative":"absolute",n.noJavaScriptRenderPathPrefixes||=[],n.seedPaths||=[],n.generated404RequestPath=yt(n.generated404RequestPath),n.sitemapPaths||=["/sitemap_index.xml","/sitemap.xml"],n.allowedAssetHosts||=[],n.assetPathPrefixes||=["/wp-content/","/wp-includes/","/static/","/assets/","/build/","/_next/","/docs/","/sitemap","/robots.txt","/llms.txt"],n.blockedPathPrefixes||=[],n.blockedSearchFragments||=[],n.concurrency||=1,n.maxPages||=0,n.extraReplacements=de(n.extraReplacements),n.postCrawlCopyMap=de(n.postCrawlCopyMap),n.logDir=String(n.logDir||"logs").trim()||"logs",n.verbose??=false,n.logLevel||=n.verbose?"debug":"info",n.s3SyncMode||="sdk-upload-delete",n.readiness||={waitForSelector:null,waitForFunction:null,timeoutMs:1500,fallbackWaitMs:1500},n.readiness.timeoutMs??=1500,n.readiness.fallbackWaitMs??=1500,n.viewport||={width:1440,height:1200},n.navigationTimeoutMs||=3e4,n.assetDownloadConcurrency=Number(n.assetDownloadConcurrency)>0?Number(n.assetDownloadConcurrency):n.concurrency,n.rewriteConcurrency=Number(n.rewriteConcurrency)>0?Number(n.rewriteConcurrency):n.assetDownloadConcurrency,n.wpsuite=he(n.wpsuite),n.scheduler=Ae(void 0),n.deploymentProfiles={},n.defaultDeploymentProfile="",n.deploymentTargetOverride=String(n.deploymentTargetOverride??"").trim();let s=await Dt(n);e.onRemotePublisherConfigDiagnostic?.(s.diagnostic);let o=xt(n,s.remote),l=$t(),a=l?b.resolve(l,".."):"";return a?(o.outputDir=Ee(a,o.outputDir,"export"),o.logDir=Ee(a,o.logDir,"logs")):(b.isAbsolute(o.outputDir)||(o.outputDir=fe(o.outputDir,"export")),b.isAbsolute(o.logDir)||(o.logDir=fe(o.logDir,"logs"))),o}function Tt(t){let e=t/6e4;if(Number.isInteger(e)&&e>=1)return `${e} minute${e===1?"":"s"}`;let r=Math.ceil(t/1e3);return `${r} second${r===1?"":"s"}`}async function O(t,e,r){let i=new AbortController,n=globalThis.setTimeout(()=>{i.abort(new Error(`${t} timed out after ${Tt(e)}.`));},e);try{return await r({abortController:i,httpOptions:{abortSignal:i.signal,requestTimeout:e}})}finally{globalThis.clearTimeout(n);}}var Ct=".deploy-plan.json",Et="deploy-plan.json",Mt=".crawl-incomplete.json",At="crawl-incomplete.json";function Le(){let t=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return t.trim()?b.resolve(t):""}function kt(t){let e=String(t||"").replace(/\\/g,"/").replace(/^\/+/,"").trim(),r=b.posix.normalize(e);return !e||!r||r==="."||/^[a-zA-Z]:/.test(r)||r.startsWith("../")||r===".."?null:r}function It(t){let e=String(t||"").trim();if(!e.startsWith("/")||e.startsWith("//")||e.includes("*")||e.includes("#"))return null;try{let r=new URL(e,"https://content-sync.invalid");return r.origin!=="https://content-sync.invalid"?null:`${b.posix.normalize(r.pathname)}${r.search}`}catch{return null}}function j(t){return [...new Set(t.map(kt).filter(e=>e!==null))]}function Lt(t,e){let r={generatedAt:String(e.generatedAt||new Date().toISOString()),outputDir:b.resolve(t.outputDir),runMode:e.runMode,crawlMode:e.crawlMode,fullSyncRequired:!!e.fullSyncRequired,changedFiles:j(e.changedFiles||[]),deletedFiles:j(e.deletedFiles||[]),rewriteTargets:j(e.rewriteTargets||[])};return e.schemaVersion===2?{...r,schemaVersion:2,runMode:"content-sync",crawlMode:"incremental",fullSyncRequired:false,consumerId:String(e.consumerId||"").trim(),fromSequence:Math.max(0,Number(e.fromSequence)||0),toSequence:Math.max(0,Number(e.toSequence)||0),impactHash:String(e.impactHash||"").trim(),uploadGroups:{assets:j(e.uploadGroups?.assets||[]),content:j(e.uploadGroups?.content||[]),listings:j(e.uploadGroups?.listings||[]),sitemapLeaves:j(e.uploadGroups?.sitemapLeaves||[]),sitemapIndexes:j(e.uploadGroups?.sitemapIndexes||[])},invalidationPaths:[...new Set((e.invalidationPaths||[]).map(It).filter(i=>i!==null))].sort()}:{schemaVersion:1,...r,runMode:e.runMode}}function Ot(t){if(!t||typeof t!="object")return false;let e=t;if(e.schemaVersion===2){let r=e;return r.runMode==="content-sync"&&r.crawlMode==="incremental"&&r.fullSyncRequired===false&&typeof r.generatedAt=="string"&&typeof r.outputDir=="string"&&typeof r.consumerId=="string"&&r.consumerId.trim()!==""&&Number.isSafeInteger(r.fromSequence)&&Number.isSafeInteger(r.toSequence)&&Number(r.toSequence)>=Number(r.fromSequence)&&typeof r.impactHash=="string"&&/^[a-f0-9]{64}$/.test(r.impactHash)&&Array.isArray(r.changedFiles)&&Array.isArray(r.deletedFiles)&&Array.isArray(r.rewriteTargets)&&!!r.uploadGroups&&Array.isArray(r.uploadGroups.assets)&&Array.isArray(r.uploadGroups.content)&&Array.isArray(r.uploadGroups.listings)&&Array.isArray(r.uploadGroups.sitemapLeaves)&&Array.isArray(r.uploadGroups.sitemapIndexes)&&Array.isArray(r.invalidationPaths)}return e.schemaVersion===1&&typeof e.generatedAt=="string"&&typeof e.outputDir=="string"&&(e.runMode==="full"||e.runMode==="retry-timeouts"||e.runMode==="single-url")&&(e.crawlMode==="full"||e.crawlMode==="incremental")&&typeof e.fullSyncRequired=="boolean"&&Array.isArray(e.changedFiles)&&Array.isArray(e.deletedFiles)&&Array.isArray(e.rewriteTargets)}function Oe(t){let e=b.join(b.resolve(t.outputDir),Ct),r=Le();return r?[b.join(r,Et),e]:[e]}function jt(t){let e=b.join(b.resolve(t.outputDir),Mt),r=Le();return r?[b.join(r,At),e]:[e]}async function je(t){let e=b.resolve(t.outputDir);for(let r of Oe(t))try{let i=await R.readFile(r,"utf8"),n=JSON.parse(i);if(!Ot(n)||b.resolve(n.outputDir)!==e)continue;return Lt(t,n)}catch{}return null}async function Fe(t){for(let e of Oe(t))try{await R.unlink(e);}catch(r){if(r.code!=="ENOENT")throw r}}async function _e(t){let e=b.resolve(t.outputDir);for(let r of jt(t)){let i;try{i=await R.readFile(r,"utf8");}catch(s){if(s.code==="ENOENT")continue;throw s}let n;try{n=JSON.parse(i);}catch{throw new Error(`Invalid incomplete crawl marker: ${r}`)}if(n.schemaVersion!==1||typeof n.startedAt!="string"||typeof n.outputDir!="string"||b.resolve(n.outputDir)!==e)throw new Error(`Invalid incomplete crawl marker: ${r}`);return {schemaVersion:1,startedAt:n.startedAt,outputDir:e}}return null}function Ft(t){return typeof t.subscriptionType=="string"&&t.subscriptionType.trim()!==""}function Ue(t){let e="";for(let i=0;i<t.length;i++){let n=t[i];if(n==="--profile"){let s=(t[i+1]||"").trim();if(!s)throw new Error("Missing value for --profile.");e=s,i+=1;}else if(n.startsWith("--profile=")){let s=n.slice(10).trim();if(!s)throw new Error("Missing value for --profile.");e=s;}}let r=String(process.env.PUBLISHER_DEPLOY_PROFILE||process.env.PUBLISHER_DEPLOYMENT_PROFILE||"").trim();return e||r||null}function _t(t,e){return {...t,...e??{}}}function Ut(t,e){return {...t,...e??{},invalidationPaths:[...(e?.invalidationPaths??t.invalidationPaths)||[]]}}function Ne(t,e){let r=String(e??t.deploymentTargetOverride??"").trim();if(!Ft(t)){if(r)throw new Error(`Deployment target "${r}" requires an active WPSuite subscription and remote publisher config.`);return {name:null,profile:null,config:t}}let i=String(r||t.defaultDeploymentProfile||"").trim();if(!i)return {name:null,profile:null,config:t};let n=t.deploymentProfiles?.[i];if(!n)throw new Error(`Unknown deployment profile "${i}". Check the linked WPSuite publisher configuration.`);return {name:i,profile:n,config:{...t,targetOrigin:n.targetOrigin??t.targetOrigin,s3:_t(t.s3,n.s3),cloudFront:Ut(t.cloudFront,n.cloudFront)}}}var We={error:0,warn:1,info:2,debug:3},ze=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"",ne=ze?b.join(ze,"current-progress.json"):"",qe=Promise.resolve();function Be(t){return t.includes("crawl")?"crawl":t.includes("deploy")?"deploy":t.includes("invalidate")?"invalidate":t}function Nt(t,e){let r={...t},i=new Set(["pagesQueued","pagesRendered","assetsQueued","sitemapsQueued","pagesDiscovered","assetsDiscovered","sitemapsDiscovered","pagesSaved","assetsSaved","donePages","doneAssets","doneSitemaps","changedTextFiles","uploaded","failed","index","totalFiles","pageQueue","assetQueue","sitemapQueue"]);for(let[n,s]of Object.entries(e)){let o=r[n];if(typeof o=="number"&&typeof s=="number"&&i.has(n)){r[n]=Math.max(o,s);continue}r[n]=s;}return r}function Wt(t,e,r){ne&&(qe=qe.then(async()=>{let i=new Date,n=i.toISOString();await R.mkdir(b.dirname(ne),{recursive:true});let s=await R.readFile(ne,"utf8").then(w=>JSON.parse(w)).catch(()=>null),o=s&&typeof s.details=="object"&&s.details?s.details:{},l=Be(t),a=s?.currentStep||Be(s?.source||""),c=s?.startedAt||n,u={...s?.stepDurationsSec??{}},m=s?.stepStartedAt||n;if(a&&a!==l&&s?.stepStartedAt){let w=Math.max(0,Math.round((i.getTime()-new Date(s.stepStartedAt).getTime())/1e3));u[a]=(u[a]??0)+w,m=n;}let p=Math.max(0,Math.round((i.getTime()-new Date(m).getTime())/1e3)),d=Math.max(0,Math.round((i.getTime()-new Date(c).getTime())/1e3)),g={checkedAt:n,source:t,message:e,details:Nt(o,r??{}),startedAt:c,currentStep:l,stepStartedAt:m,stepElapsedSec:p,totalElapsedSec:d,stepDurationsSec:u};await R.writeFile(ne,JSON.stringify(g,null,2),"utf8");}).catch(()=>{}));}async function zt(t,e){await R.mkdir(b.dirname(t),{recursive:true}),await R.appendFile(t,`${JSON.stringify(e)}
|
|
2
|
-
`,"utf8");}var
|
|
3
|
-
`,"utf8");});}enqueueJsonLine(e,r){this.enqueueTask(()=>
|
|
1
|
+
import D from'fs/promises';import wt from'http';import bt from'https';import b from'path';import {S3Client,HeadObjectCommand,GetObjectCommand,DeleteObjectsCommand,ListObjectsV2Command}from'@aws-sdk/client-s3';import {Upload}from'@aws-sdk/lib-storage';import Kt,{createHash}from'crypto';import Qt from'fast-glob';import Rr from'mime-types';import {availableParallelism}from'os';import {Worker}from'worker_threads';function Me(t){let e=t.trim();return e==="."?".":e.replace(/\/$/,"")}function Pt(t){let e=String(t??"").trim();if(!e)return "";let r=e;if(/^https?:\/\//i.test(r))try{r=new URL(r).pathname;}catch{return ""}if(r=r.split(/[?#]/,1)[0]?.replace(/\\/g,"/").trim()??"",!r)return "";let i=r.endsWith("/"),n=r.replace(/^\/+/,"").split("/").map(o=>o.replace(/[^A-Za-z0-9._-]/g,"")).filter(o=>o.length>0&&o!=="."&&o!=="..");if(n.length===0)return "";let s=`/${n.join("/")}`;return i&&b.extname(s)===""&&(s+="/"),s==="/"?"":s}function me(t){return !t||typeof t!="object"?{}:Object.fromEntries(Object.entries(t).map(([e,r])=>[e.trim(),String(r??"")]).filter(([e])=>e.length>0))}function St(t){if(!t||typeof t!="object")return {};let e={};for(let[r,i]of Object.entries(t)){let n=r.trim();if(!n||!i||typeof i!="object")continue;let s=i,o={};if(typeof s.targetOrigin=="string"){let a=Me(s.targetOrigin);a&&(o.targetOrigin=a);}let l=me(s.extraReplacements);if(Object.keys(l).length>0&&(o.extraReplacements=l),s.s3&&typeof s.s3=="object"){let a={},c=s.s3;typeof c.bucket=="string"&&(a.bucket=c.bucket.trim()),typeof c.prefix=="string"&&(a.prefix=c.prefix.trim()),typeof c.region=="string"&&(a.region=c.region.trim()),typeof c.htmlCacheControl=="string"&&(a.htmlCacheControl=c.htmlCacheControl.trim()),typeof c.assetCacheControl=="string"&&(a.assetCacheControl=c.assetCacheControl.trim()),Object.keys(a).length>0&&(o.s3=a);}if(s.cloudFront&&typeof s.cloudFront=="object"){let a={},c=s.cloudFront;typeof c.distributionId=="string"&&(a.distributionId=c.distributionId.trim()),Array.isArray(c.invalidationPaths)&&(a.invalidationPaths=c.invalidationPaths.map(u=>String(u??"").trim()).filter(u=>u.length>0)),Object.keys(a).length>0&&(o.cloudFront=a);}e[n]=o;}return e}function ye(t){return t==="PROFESSIONAL"||t==="AGENCY"?t:void 0}function vt(t,e){if(!t||typeof t!="object")return null;let r=t,i=r.command;if(i!=="publish"&&i!=="crawl"&&i!=="deploy"&&i!=="invalidate"&&i!=="retry-timeouts"&&i!=="url"&&i!=="content-sync")return null;let n=Number.parseInt(String(r.intervalMinutes??"0"),10);if(!Number.isFinite(n)||n<1)return null;let s=String(r.id??`${i}-${e+1}`).trim();if(!s)return null;let o=String(r.deploymentProfile??"").trim(),l=String(r.url??"").trim(),a=Array.isArray(r.postTypes)?[...new Set(r.postTypes.map(u=>String(u??"").trim().toLowerCase().replace(/[^a-z0-9_-]/g,"")).filter(Boolean))]:[],c=Array.isArray(r.listingPaths)?[...new Set(r.listingPaths.map(u=>String(u??"").trim()).filter(Boolean))]:[];return i==="content-sync"&&a.length===0?null:{id:s,enabled:r.enabled!==false,command:i,intervalMinutes:n,...i==="publish"||i==="crawl"?{crawlMode:r.crawlMode==="incremental"?"incremental":"full"}:{},...(i==="publish"||i==="deploy"||i==="invalidate"||i==="content-sync")&&o?{deploymentProfile:o}:{},...l?{url:l}:{},...a.length>0?{postTypes:a}:{},...c.length>0?{listingPaths:c}:{},...typeof r.includePostTypeArchives=="boolean"?{includePostTypeArchives:r.includePostTypeArchives}:{},...typeof r.includeTaxonomyArchives=="boolean"?{includeTaxonomyArchives:r.includeTaxonomyArchives}:{},...typeof r.includeAuthorArchives=="boolean"?{includeAuthorArchives:r.includeAuthorArchives}:{},...typeof r.includeDateArchives=="boolean"?{includeDateArchives:r.includeDateArchives}:{},...typeof r.includePostsPage=="boolean"?{includePostsPage:r.includePostsPage}:{},...typeof r.includeSitemapChain=="boolean"?{includeSitemapChain:r.includeSitemapChain}:{}}}function Ie(t){let e=t&&typeof t=="object"?t:{},r=Array.isArray(e.rules)?e.rules.map((i,n)=>vt(i,n)).filter(i=>!!i):[];return {enabled:e.enabled===true,timezone:typeof e.timezone=="string"&&e.timezone.trim()!==""?e.timezone.trim():"UTC",rules:r}}function Rt(t){if(!t||typeof t!="object")return;let e=t,r={};for(let n of ["accountId","siteId"]){let s=e[n];typeof s=="string"&&s.trim()!==""&&(r[n]=s.trim());}let i=Number(e.lastUpdate??0);return Number.isFinite(i)&&i>0&&(r.lastUpdate=Math.floor(i)),e.subscriber===true&&(r.subscriber=true),Object.keys(r).length>0?r:void 0}function we(t){let e=t&&typeof t=="object"?t:{},r=String(e.accountId??"").trim(),i=String(e.siteId??"").trim(),n=e.subscriber===true,s=Rt(e.siteSettings),o={...s??{},...r?{accountId:s?.accountId??r}:{},...i?{siteId:s?.siteId??i}:{},...s?.subscriber===true||n?{subscriber:true}:{}},l={},a=String(e.apiBase??"").trim();a&&(l.apiBase=a);let c=String(e.runtimeToken??e.nonce??"").trim();c&&(l.runtimeToken=c);let u=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();u&&(l.virtualAssetBaseUrl=u),Object.keys(o).length>0&&(l.siteSettings=o);let m=ye(e.subscriptionType);return m&&(l.subscriptionType=m),l}function Dt(t){try{let e=new URL(t);globalThis.location=e;}catch{}}function Le(t){return typeof t=="string"?t:t instanceof URL?t.toString():t.url}function xt(t,e){let r=new Headers(t instanceof Request?t.headers:void 0);if(e?.headers)for(let[i,n]of new Headers(e.headers).entries())r.set(i,n);return r}async function Oe(t,e,r=5){let i=new URL(Le(t)),n=String(e?.method??(t instanceof Request?t.method:"GET")).toUpperCase(),s=i.protocol==="http:"?wt:bt,o=xt(t,e);return await new Promise((l,a)=>{let c=s.request(i,{method:n,headers:Object.fromEntries(o.entries()),...i.protocol==="https:"?{rejectUnauthorized:false}:{}},u=>{let m=[];u.on("data",p=>{m.push(Buffer.isBuffer(p)?p:Buffer.from(p));}),u.on("error",a),u.on("end",()=>{let p=u.statusCode??0,d=u.headers.location;if(r>0&&d&&[301,302,303,307,308].includes(p)){l(Oe(new URL(d,i),{method:p===303?"GET":n},r-1));return}let g=new Headers;for(let[w,T]of Object.entries(u.headers))Array.isArray(T)?g.set(w,T.join(", ")):typeof T=="string"&&g.set(w,T);l(new Response(Buffer.concat(m),{status:p,statusText:u.statusMessage??"",headers:g}));});});c.on("error",a),c.end();})}function $t(t){let e=we(t.wpsuite),r={...e.siteSettings??{},...e.siteSettings?.subscriber===true||e.subscriptionType==="PROFESSIONAL"||e.subscriptionType==="AGENCY"?{subscriber:true}:{}},i=String(r.accountId??"").trim(),n=String(r.siteId??"").trim(),s=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();if(t.wpsuite={...e.apiBase?{apiBase:e.apiBase}:{},...e.runtimeToken?{runtimeToken:e.runtimeToken}:{},...s?{virtualAssetBaseUrl:s}:{},...Object.keys(r).length>0?{siteSettings:r}:{},...e.subscriptionType?{subscriptionType:e.subscriptionType}:{}},!i||!n||!s)return false;Dt(t.sourceOrigin);let o=globalThis,a={...o.WpSuite??{},siteSettings:r,uploadUrl:s};return e.apiBase&&(a.apiBase=e.apiBase),o.WpSuite=a,true}async function Tt(t){let e=String(t.wpsuite?.virtualAssetBaseUrl??t.wpsuite?.uploadUrl??"").trim();if(!$t(t)){let n=t.wpsuite?.siteSettings,s=[String(n?.accountId??"").trim()?"":"accountId",String(n?.siteId??"").trim()?"":"siteId",e?"":"virtualAssetBaseUrl"].filter(Boolean);return {remote:null,diagnostic:{status:"invalid-runtime",virtualAssetBaseUrl:e,subscriptionType:null,error:`Missing WP Suite runtime field(s): ${s.join(", ")}.`,requests:[]}}}let r=globalThis.fetch,i=[];try{typeof r=="function"&&/^https?:\/\//i.test(e)&&(globalThis.fetch=(async(a,c)=>{let u=Le(a);if(u.startsWith(e)){let m=(()=>{try{return new URL(u).pathname}catch{return u}})();try{let p=t.ignoreHttpsErrors&&u.startsWith("https://")?await Oe(a,c):await r(a,c);return i.push({path:m,status:p.status,ok:p.ok,error:null}),p}catch(p){throw i.push({path:m,status:null,ok:!1,error:p instanceof Error?p.message:String(p)}),p}}return r(a,c)}));let{getConfig:n}=await import('@smart-cloud/wpsuite-core'),s=await n("publisher"),o=s&&typeof s=="object"?s:null,l=ye(o?.subscriptionType);return {remote:o,diagnostic:{status:o?"loaded":"unavailable",virtualAssetBaseUrl:e,subscriptionType:l??null,error:o?null:"WP Suite publisher config loader returned no configuration.",requests:i}}}catch(n){return {remote:null,diagnostic:{status:"unavailable",virtualAssetBaseUrl:e,subscriptionType:null,error:n instanceof Error?n.message:String(n),requests:i}}}finally{typeof r=="function"&&(globalThis.fetch=r);}}function Et(t,e){let r=St(e?.deploymentProfiles),i=String(e?.defaultDeploymentProfile??"").trim(),n=r[i]?i:"",s=ye(e?.subscriptionType),o=we(t.wpsuite);return {...t,scheduler:Ie(e?.scheduler),deploymentProfiles:r,defaultDeploymentProfile:n,...s?{subscriptionType:s}:{},wpsuite:{...o,...o.siteSettings||s?{siteSettings:{...o.siteSettings??{},...o.siteSettings?.subscriber===true||s==="PROFESSIONAL"||s==="AGENCY"?{subscriber:true}:{}}}:{},...s?{subscriptionType:s}:{}}}}function he(t,e){let i=String(t||"").replace(/\\/g,"/").trim().replace(/^\/+|\/+$/g,"");if(!i)return e;let n=i.split("/").map(s=>s.trim()).filter(s=>s.length>0&&s!=="."&&s!=="..");return n.length>0?n.join("/"):e}function Ct(){let t=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return t.trim()?b.resolve(t):""}function Ae(t,e,r){let i=String(e||"").trim();return i&&b.isAbsolute(i)?b.resolve(i):b.resolve(t,he(i,r))}async function ne(t,e={}){let r=String("").trim()||process.env.PUBLISHER_CONFIG||"publisher.config.json",i=await D.readFile(r,"utf8"),n=JSON.parse(i);n.sourceOrigin=n.sourceOrigin.replace(/\/$/,""),n.targetOrigin=Me(n.targetOrigin),n.ignoreHttpsErrors??=false,n.outputDir=String(n.outputDir||"export").trim()||"export",n.urlRewriteMode||=n.targetOrigin==="."?"relative":"absolute",n.noJavaScriptRenderPathPrefixes||=[],n.seedPaths||=[],n.generated404RequestPath=Pt(n.generated404RequestPath),n.sitemapPaths||=["/sitemap_index.xml","/sitemap.xml"],n.allowedAssetHosts||=[],n.assetPathPrefixes||=["/wp-content/","/wp-includes/","/static/","/assets/","/build/","/_next/","/docs/","/sitemap","/robots.txt","/llms.txt"],n.blockedPathPrefixes||=[],n.blockedSearchFragments||=[],n.concurrency||=1,n.maxPages||=0,n.extraReplacements=me(n.extraReplacements),n.postCrawlCopyMap=me(n.postCrawlCopyMap),n.logDir=String(n.logDir||"logs").trim()||"logs",n.verbose??=false,n.logLevel||=n.verbose?"debug":"info",n.s3SyncMode||="sdk-upload-delete",n.readiness||={waitForSelector:null,waitForFunction:null,timeoutMs:1500,fallbackWaitMs:1500},n.readiness.timeoutMs??=1500,n.readiness.fallbackWaitMs??=1500,n.viewport||={width:1440,height:1200},n.navigationTimeoutMs||=3e4,n.assetDownloadConcurrency=Number(n.assetDownloadConcurrency)>0?Number(n.assetDownloadConcurrency):n.concurrency,n.rewriteConcurrency=Number(n.rewriteConcurrency)>0?Number(n.rewriteConcurrency):n.assetDownloadConcurrency,n.wpsuite=we(n.wpsuite),n.scheduler=Ie(void 0),n.deploymentProfiles={},n.defaultDeploymentProfile="",n.deploymentTargetOverride=String(n.deploymentTargetOverride??"").trim();let s=await Tt(n);e.onRemotePublisherConfigDiagnostic?.(s.diagnostic);let o=Et(n,s.remote),l=Ct(),a=l?b.resolve(l,".."):"";return a?(o.outputDir=Ae(a,o.outputDir,"export"),o.logDir=Ae(a,o.logDir,"logs")):(b.isAbsolute(o.outputDir)||(o.outputDir=he(o.outputDir,"export")),b.isAbsolute(o.logDir)||(o.logDir=he(o.logDir,"logs"))),o}function kt(t){let e=t/6e4;if(Number.isInteger(e)&&e>=1)return `${e} minute${e===1?"":"s"}`;let r=Math.ceil(t/1e3);return `${r} second${r===1?"":"s"}`}async function O(t,e,r){let i=new AbortController,n=globalThis.setTimeout(()=>{i.abort(new Error(`${t} timed out after ${kt(e)}.`));},e);try{return await r({abortController:i,httpOptions:{abortSignal:i.signal,requestTimeout:e}})}finally{globalThis.clearTimeout(n);}}var At=".deploy-plan.json",Mt="deploy-plan.json",It=".crawl-incomplete.json",Lt="crawl-incomplete.json";function je(){let t=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return t.trim()?b.resolve(t):""}function Ot(t){let e=String(t||"").replace(/\\/g,"/").replace(/^\/+/,"").trim(),r=b.posix.normalize(e);return !e||!r||r==="."||/^[a-zA-Z]:/.test(r)||r.startsWith("../")||r===".."?null:r}function jt(t){let e=String(t||"").trim();if(!e.startsWith("/")||e.startsWith("//")||e.includes("*")||e.includes("#"))return null;try{let r=new URL(e,"https://content-sync.invalid");return r.origin!=="https://content-sync.invalid"?null:`${b.posix.normalize(r.pathname)}${r.search}`}catch{return null}}function j(t){return [...new Set(t.map(Ot).filter(e=>e!==null))]}function Ft(t,e){let r={generatedAt:String(e.generatedAt||new Date().toISOString()),outputDir:b.resolve(t.outputDir),runMode:e.runMode,crawlMode:e.crawlMode,fullSyncRequired:!!e.fullSyncRequired,changedFiles:j(e.changedFiles||[]),deletedFiles:j(e.deletedFiles||[]),rewriteTargets:j(e.rewriteTargets||[])};return e.schemaVersion===2?{...r,schemaVersion:2,runMode:"content-sync",crawlMode:"incremental",fullSyncRequired:false,consumerId:String(e.consumerId||"").trim(),fromSequence:Math.max(0,Number(e.fromSequence)||0),toSequence:Math.max(0,Number(e.toSequence)||0),impactHash:String(e.impactHash||"").trim(),uploadGroups:{assets:j(e.uploadGroups?.assets||[]),content:j(e.uploadGroups?.content||[]),listings:j(e.uploadGroups?.listings||[]),sitemapLeaves:j(e.uploadGroups?.sitemapLeaves||[]),sitemapIndexes:j(e.uploadGroups?.sitemapIndexes||[])},invalidationPaths:[...new Set((e.invalidationPaths||[]).map(jt).filter(i=>i!==null))].sort()}:{schemaVersion:1,...r,runMode:e.runMode}}function _t(t){if(!t||typeof t!="object")return false;let e=t;if(e.schemaVersion===2){let r=e;return r.runMode==="content-sync"&&r.crawlMode==="incremental"&&r.fullSyncRequired===false&&typeof r.generatedAt=="string"&&typeof r.outputDir=="string"&&typeof r.consumerId=="string"&&r.consumerId.trim()!==""&&Number.isSafeInteger(r.fromSequence)&&Number.isSafeInteger(r.toSequence)&&Number(r.toSequence)>=Number(r.fromSequence)&&typeof r.impactHash=="string"&&/^[a-f0-9]{64}$/.test(r.impactHash)&&Array.isArray(r.changedFiles)&&Array.isArray(r.deletedFiles)&&Array.isArray(r.rewriteTargets)&&!!r.uploadGroups&&Array.isArray(r.uploadGroups.assets)&&Array.isArray(r.uploadGroups.content)&&Array.isArray(r.uploadGroups.listings)&&Array.isArray(r.uploadGroups.sitemapLeaves)&&Array.isArray(r.uploadGroups.sitemapIndexes)&&Array.isArray(r.invalidationPaths)}return e.schemaVersion===1&&typeof e.generatedAt=="string"&&typeof e.outputDir=="string"&&(e.runMode==="full"||e.runMode==="retry-timeouts"||e.runMode==="single-url")&&(e.crawlMode==="full"||e.crawlMode==="incremental")&&typeof e.fullSyncRequired=="boolean"&&Array.isArray(e.changedFiles)&&Array.isArray(e.deletedFiles)&&Array.isArray(e.rewriteTargets)}function Fe(t){let e=b.join(b.resolve(t.outputDir),At),r=je();return r?[b.join(r,Mt),e]:[e]}function Ut(t){let e=b.join(b.resolve(t.outputDir),It),r=je();return r?[b.join(r,Lt),e]:[e]}async function _e(t){let e=b.resolve(t.outputDir);for(let r of Fe(t))try{let i=await D.readFile(r,"utf8"),n=JSON.parse(i);if(!_t(n)||b.resolve(n.outputDir)!==e)continue;return Ft(t,n)}catch{}return null}async function Ue(t){for(let e of Fe(t))try{await D.unlink(e);}catch(r){if(r.code!=="ENOENT")throw r}}async function Ne(t){let e=b.resolve(t.outputDir);for(let r of Ut(t)){let i;try{i=await D.readFile(r,"utf8");}catch(s){if(s.code==="ENOENT")continue;throw s}let n;try{n=JSON.parse(i);}catch{throw new Error(`Invalid incomplete crawl marker: ${r}`)}if(n.schemaVersion!==1||typeof n.startedAt!="string"||typeof n.outputDir!="string"||b.resolve(n.outputDir)!==e)throw new Error(`Invalid incomplete crawl marker: ${r}`);return {schemaVersion:1,startedAt:n.startedAt,outputDir:e}}return null}function Nt(t){return typeof t.subscriptionType=="string"&&t.subscriptionType.trim()!==""}function ze(t){let e="";for(let i=0;i<t.length;i++){let n=t[i];if(n==="--profile"){let s=(t[i+1]||"").trim();if(!s)throw new Error("Missing value for --profile.");e=s,i+=1;}else if(n.startsWith("--profile=")){let s=n.slice(10).trim();if(!s)throw new Error("Missing value for --profile.");e=s;}}let r=String(process.env.PUBLISHER_DEPLOY_PROFILE||process.env.PUBLISHER_DEPLOYMENT_PROFILE||"").trim();return e||r||null}function zt(t,e){return {...t,...e??{}}}function Wt(t,e){return {...t,...e??{},invalidationPaths:[...(e?.invalidationPaths??t.invalidationPaths)||[]]}}function We(t,e){let r=String(e??t.deploymentTargetOverride??"").trim();if(!Nt(t)){if(r)throw new Error(`Deployment target "${r}" requires an active WPSuite subscription and remote publisher config.`);return {name:null,profile:null,config:t}}let i=String(r||t.defaultDeploymentProfile||"").trim();if(!i)return {name:null,profile:null,config:t};let n=t.deploymentProfiles?.[i];if(!n)throw new Error(`Unknown deployment profile "${i}". Check the linked WPSuite publisher configuration.`);return {name:i,profile:n,config:{...t,targetOrigin:n.targetOrigin??t.targetOrigin,s3:zt(t.s3,n.s3),cloudFront:Wt(t.cloudFront,n.cloudFront)}}}var qe={error:0,warn:1,info:2,debug:3},qt=/^(?:authorization|proxyAuthorization|runtimeToken|siteKey|nonce|accessToken|refreshToken|accessKeyId|secretAccessKey|sessionToken|xStaticPublisherToken|xApiKey)$/i;function ee(t){return t.replace(/((?:x-static-publisher-token|authorization|proxy-authorization|x-api-key|aws-access-key-id|aws-secret-access-key|aws-session-token)\s*:\s*)[^\r\n]+/gi,"$1[REDACTED]").replace(/\b(Basic|Bearer)\s+[^\s]+/gi,"$1 [REDACTED]").replace(/([?&](?:token|access_token|refresh_token|api_key|key|nonce)=)[^&\s]+/gi,"$1[REDACTED]").replace(/((?:"|')?(?:runtimeToken|siteKey|nonce|accessToken|refreshToken|accessKeyId|secretAccessKey|sessionToken)(?:"|')?\s*[:=]\s*(?:"|'))[^"']+/gi,"$1[REDACTED]")}function se(t){return typeof t=="string"?ee(t):Array.isArray(t)?t.map(e=>se(e)):t instanceof Error?{name:t.name,message:ee(t.message),...t.stack?{stack:ee(t.stack)}:{}}:t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([e,r])=>[e,qt.test(e)?"[REDACTED]":se(r)])):t}function Ke(t){return t?se(t):void 0}var Be=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"",ie=Be?b.join(Be,"current-progress.json"):"",Ge=Promise.resolve();function He(t){return t.includes("crawl")?"crawl":t.includes("deploy")?"deploy":t.includes("invalidate")?"invalidate":t}function Bt(t,e){let r={...t},i=new Set(["pagesQueued","pagesRendered","assetsQueued","sitemapsQueued","pagesDiscovered","assetsDiscovered","sitemapsDiscovered","pagesSaved","assetsSaved","donePages","doneAssets","doneSitemaps","changedTextFiles","uploaded","failed","index","totalFiles","pageQueue","assetQueue","sitemapQueue"]);for(let[n,s]of Object.entries(e)){let o=r[n];if(typeof o=="number"&&typeof s=="number"&&i.has(n)){r[n]=Math.max(o,s);continue}r[n]=s;}return r}function Gt(t,e,r){ie&&(Ge=Ge.then(async()=>{let i=new Date,n=i.toISOString();await D.mkdir(b.dirname(ie),{recursive:true});let s=await D.readFile(ie,"utf8").then(S=>JSON.parse(S)).catch(()=>null),o=s&&typeof s.details=="object"&&s.details?s.details:{},l=He(t),a=s?.currentStep||He(s?.source||""),c=s?.startedAt||n,u={...s?.stepDurationsSec??{}},m=s?.stepStartedAt||n;if(a&&a!==l&&s?.stepStartedAt){let S=Math.max(0,Math.round((i.getTime()-new Date(s.stepStartedAt).getTime())/1e3));u[a]=(u[a]??0)+S,m=n;}let p=Math.max(0,Math.round((i.getTime()-new Date(m).getTime())/1e3)),d=Math.max(0,Math.round((i.getTime()-new Date(c).getTime())/1e3)),g=ee(e),w=Ke(r)??{},T={checkedAt:n,source:t,message:g,details:Bt(o,w),startedAt:c,currentStep:l,stepStartedAt:m,stepElapsedSec:p,totalElapsedSec:d,stepDurationsSec:u};await D.writeFile(ie,JSON.stringify(T,null,2),"utf8");}).catch(()=>{}));}async function Ht(t,e){await D.mkdir(b.dirname(t),{recursive:true}),await D.appendFile(t,`${JSON.stringify(se(e))}
|
|
2
|
+
`,"utf8");}var G=class{constructor(e,r,i="info"){this.logDir=e;this.logFile=r;this.level=i;this.ensureLogFileReady();}logDir;logFile;level;startedAt=Date.now();marks=new Map;initPromise=null;writeQueue=Promise.resolve();writeError=null;get logPath(){return b.join(this.logDir,this.logFile)}artifactPath(e){return this.logFile.endsWith(".log.jsonl")?b.join(this.logDir,this.logFile.replace(/\.log\.jsonl$/u,`${e}.jsonl`)):b.join(this.logDir,`${this.logFile}${e}.jsonl`)}get errorsPath(){return this.artifactPath(".errors")}get rejectedPath(){return this.artifactPath(".rejected")}ensureLogFileReady(){return this.initPromise||(this.initPromise=(async()=>{await D.mkdir(this.logDir,{recursive:true}),await D.writeFile(this.logPath,"","utf8");})()),this.initPromise}enqueueTask(e){this.writeQueue=this.writeQueue.then(e).catch(r=>{this.writeError=r instanceof Error?r:new Error(String(r));});}enqueueLine(e){this.enqueueTask(async()=>{await this.ensureLogFileReady(),await D.appendFile(this.logPath,`${e}
|
|
3
|
+
`,"utf8");});}enqueueJsonLine(e,r){this.enqueueTask(()=>Ht(e,r));}accepts(e){return qe[e]<=qe[this.level]}push(e,r,i){if(!this.accepts(e))return;let n=ee(r),s=Ke(i),o=JSON.stringify({time:new Date().toISOString(),level:e,message:n,...s||{}});this.enqueueLine(o),e==="error"?console.error(`[ERROR] ${n}`,s?JSON.stringify(s):""):e==="warn"?console.warn(`[WARN] ${n}`,s?JSON.stringify(s):""):console.log(`[${e.toUpperCase().padEnd(5)}] ${n}`);}info(e,r){this.push("info",e,r);}progress(e,r){Gt(this.logFile,e,r);}debug(e,r){this.push("debug",e,r);}warn(e,r){this.push("warn",e,r);}reject(e,r,i,n,s){let o={kind:e,url:r,reason:i,...n?{source:n}:{},...s||{}};this.enqueueJsonLine(this.rejectedPath,o),this.accepts("debug")&&this.push("debug",`Rejected ${e} ${r}: ${i}`,o);}error(e,r){this.enqueueJsonLine(this.errorsPath,{message:e,...r||{}}),this.push("error",e,r);}mark(e){this.marks.set(e,Date.now());}endMark(e,r){let i=this.marks.get(e);if(!i)return;let n=Date.now()-i,s=Number((n/1e3).toFixed(2));this.push("info",`Timing ${e}: ${s}s`,{name:e,ms:n,seconds:s,...r||{}});}async flush(){let e=Date.now()-this.startedAt,r=Number((e/1e3).toFixed(2));if(this.push("info",`Total time: ${r}s`,{name:"total",ms:e,seconds:r}),await this.writeQueue,this.writeError)throw this.writeError}};async function Jt(t){await D.mkdir(b.dirname(t),{recursive:true});}async function Qe(t,e,r){await Jt(t);let i=b.join(b.dirname(t),`.${b.basename(t)}.${process.pid}.${Date.now()}.${Kt.randomBytes(6).toString("hex")}.tmp`);try{typeof e=="string"?await D.writeFile(i,e,r??"utf8"):await D.writeFile(i,e),await D.rename(i,t);}catch(n){throw await D.unlink(i).catch(()=>{}),n}}function Ye(t){return [".html",".htm",".css",".js",".mjs",".json",".xml",".xsl",".txt",".svg",".map",".enc",".jws"].includes(b.extname(t).toLowerCase())}function Ze(t){return t.replace(/"/g,'"').replace(/"/g,'"').replace(/'/g,"'").replace(/'/g,"'").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function H(t){return t.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}function oe(t){return t.replace(/\//g,"\\/")}function Je(t){return t.replace(/\//g,"\\\\/")}function Vt(t){try{let e=new URL(t);if(e.protocol!=="http:"&&e.protocol!=="https:")return null;let r=e.pathname==="/"&&!e.search&&!e.hash?"":`${e.pathname}${e.search}${e.hash}`;return `//${e.host}${r}`}catch{return null}}function Ve(t,e,r){if(!e)return;t[e]=r;let i=oe(e),n=oe(r);t[i]=n;let s=Je(e),o=Je(r);t[s]=o;let l=H(e),a=H(r);t[l]=a;let c=H(i),u=H(n);t[c]=u;let m=H(s),p=H(o);t[m]=p;}function ae(t,e,r){Ve(t,e,r);let i=Vt(e);i&&i!==e&&Ve(t,i,r);}function Xe(t,e){try{return new URL(t,e==="."?"https://relative.invalid":e).pathname}catch{return t.startsWith("/")?t:`/${t.replace(/^\.\//,"")}`}}function et(t,e,r){if(!e)return r;let i=b.dirname(b.resolve(e)),n=b.resolve(t,r.replace(/^\/+/,"")),s=b.relative(i,n).replace(/\\/g,"/");return s?(s.startsWith(".")||(s=`./${s}`),s):"."}var er=["wp-content/","wp-includes/","wp-admin/","wp-json/","_next/"],tr=new Set([".html",".htm"]),tt="WPSuite.io Static Publisher",rr=tt.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");function nr(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ir(t){return t.startsWith("//")||t.startsWith("\\/\\/")||t.startsWith("\\\\/\\\\/")}function sr(t,e,r){return ir(e)?t.replace(new RegExp(`(?<!:)${nr(e)}`,"g"),r):t.split(e).join(r)}function or(t,e,r){if(t.wpsuite?.siteSettings?.subscriber===true||t.wpsuite?.subscriptionType==="PROFESSIONAL"||t.wpsuite?.subscriptionType==="AGENCY"||!r)return false;let n=b.extname(r).toLowerCase();return tr.has(n)?/<head\b|<html\b|<!doctype html/i.test(e):false}function ar(t){if(new RegExp(`<meta\\b(?=[^>]*\\bname=(["'])generator\\1)(?=[^>]*\\bcontent=(["'])${rr}\\2)[^>]*\\/?>`,"i").test(t))return t;let e=`<meta name="generator" content="${tt}" />`;if(t.match(/(\r?\n)([ \t]*)<\/head>/i))return t.replace(/(\r?\n)([ \t]*)<\/head>/i,`$1$2${e}$1$2</head>`);let i=t.includes(`\r
|
|
4
4
|
`)?`\r
|
|
5
5
|
`:`
|
|
6
|
-
`;return t.replace(/<head\b[^>]*>/i,n=>`${n}${i} ${e}`)}function ir(t){let e=Ve(t).trim();return e.startsWith("{")||e.startsWith("[")||e.includes("\\/")||/"@context"|"@type"/.test(e)}function sr(t,e){let r=[...new Set(e)].filter(s=>s.includes("/")&&!/\\+\//.test(s)).map(s=>[s,ie(s)]).filter(([s,o])=>s!==o).sort((s,o)=>o[0].length-s[0].length);if(!r.length)return t;let i=s=>{let o=s;for(let[l,a]of r)o=o.split(l).join(a);return o},n=t.replace(/(<script\b[^>]*\btype=["']application\/(?:ld\+)?json["'][^>]*>)([\s\S]*?)(<\/script>)/gi,(s,o,l,a)=>`${o}${i(l)}${a}`);return n=n.replace(/(<meta\b[^>]*\bcontent=(['"]))([\s\S]*?)(\2[^>]*>)/gi,(s,o,l,a,c)=>ir(a)?`${o}${i(a)}${c}`:s),n}function or(t,e){if(!e)return null;let r=b.dirname(b.resolve(e)),i=b.resolve(t.outputDir),n=b.relative(r,i).replace(/\\/g,"/");return n?(n.startsWith(".")||(n=`./${n}`),n.endsWith("/")?n:`${n}/`):"./"}function ar(t,e,r){let i=or(e,r);if(!i)return t;let n=t;for(let s of Qt){let o=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),l=new RegExp(`(?:\\.{1,}/)+${o}`,"g"),a=new RegExp(`(?<!\\.)/${o}`,"g");n=n.replace(l,`${i}${s}`).replace(a,`${i}${s}`);let c=s.replace(/\//g,"\\/"),u=i.replace(/\//g,"\\/"),m=c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),p=new RegExp(`(?:\\.{1,}\\\\/)+${m}`,"g"),d=new RegExp(`(?:\\.{1,}(?:\\\\/|\\\\))+${m}`,"g"),g=new RegExp(`(?<![\\.\\\\])\\/${m}`,"g");n=n.replace(p,`${u}${c}`).replace(d,`${u}${c}`).replace(g,`${u}${c}`);}return n}function be(t,e,r){if(t.urlRewriteMode==="absolute")return e;let i=(()=>{try{return new URL(e,t.targetOrigin==="."?"https://relative.invalid":t.targetOrigin)}catch{return null}})(),n=i?i.pathname:Qe(e,t.targetOrigin),s=i?`${i.search}${i.hash}`:"";return t.urlRewriteMode==="root-relative"?`${n}${s}`:`${Ye(t.outputDir,r,n)}${s}`}function we(t,e,r,i,n){se(t,r,be(e,i,n));}function lr(t,e,r,i,n){if(!r||r===i)return;se(t,r,i);let s=be(e,r,n),o=be(e,i,n);se(t,s,o);}function ur(t,e,r,i,n={}){let s=t,o={};we(o,e,e.sourceOrigin,e.targetOrigin,i);for(let[a,c]of Object.entries(e.extraReplacements))we(o,e,a,c,i);for(let[a,c]of Object.entries(r))we(o,e,a,c,i);for(let[a,c]of Object.entries(n)){let u=r[a];!u||u===c||lr(o,e,c,u,i);}let l=Object.entries(o).sort((a,c)=>c[0].length-a[0].length);for(let[a,c]of l)s=tr(s,a,c);return e.urlRewriteMode!=="absolute"&&(s=ar(s,e,i)),s=sr(s,l.map(([,a])=>a)),rr(e,s,i)&&(s=nr(s)),s}async function cr(t,e,r,i){let n=b.join(t.outputDir,i),s=b.extname(n).toLowerCase(),o;try{o=await R.readFile(n,"utf8");}catch(c){if(c.code!=="ENOENT")throw c;return {changed:false}}let a=ur(o,t,e,s===".js"||s===".mjs"?void 0:n,r);return a!==o?(await Je(n,a,"utf8"),{changed:true}):{changed:false}}async function gr(t,e){return await new Promise((r,i)=>{let n=a=>{if(l(),a?.error){i(new Error(a.error));return}r({changed:!!a?.changed});},s=a=>{l(),i(a);},o=a=>{l(),a!==0&&i(new Error(`Rewrite worker exited with code ${a}.`));},l=()=>{t.off("message",n),t.off("error",s),t.off("exit",o);};t.on("message",n),t.on("error",s),t.on("exit",o),t.postMessage({file:e});})}async function Xe(t,e,r={}){let n=(r.files?[...new Set(r.files)].map(p=>b.resolve(p)).filter(p=>p.startsWith(b.resolve(t.outputDir))).map(p=>b.relative(t.outputDir,p).replace(/\\/g,"/")).filter(p=>p.length>0):await Gt(["**/*"],{cwd:t.outputDir,onlyFiles:true,dot:true})).filter(p=>p!=="asset-map.json"&&Ke(p)),s=0;if(n.length===0)return 0;let o=Math.max(1,Number(t.rewriteConcurrency||t.assetDownloadConcurrency||1)),l=Math.max(1,Math.min(o,n.length,availableParallelism()));await r.onStart?.({totalFiles:n.length,workerCount:l});let a=0,c=0,u=null;if(l===1){for(let p of n){let d=await cr(t,e,r.previousAssetMap??{},p);d.changed&&(s+=1),c+=1,await r.onProgress?.({index:c,totalFiles:n.length,changedTextFiles:s,file:p,changed:d.changed});}return s}let m=Array.from({length:l},async()=>{let p=new Worker(new URL("./rewrite-worker.js",import.meta.url),{workerData:{config:t,assetMap:e,previousAssetMap:r.previousAssetMap??{}}});try{for(;!u;){let d=a;if(d>=n.length)return;a+=1;let g=n[d],w=await gr(p,g);w.changed&&(s+=1),c+=1,await r.onProgress?.({index:c,totalFiles:n.length,changedTextFiles:s,file:g,changed:w.changed});}}catch(d){throw u=d instanceof Error?d:new Error(String(d)),u}finally{await p.terminate().catch(()=>{});}});return await Promise.all(m),s}var nt="wpsuite-sha256",it="wpsuite-normalized-sha256",Pr=/(?:^|[-_:.])(id|uid|nonce|token|hash|instance)(?:$|[-_:.])/i,xe=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,Sr=["SIGINT","SIGTERM"],le=new Set,oe=new Map,et=null;function vr(t){le.add(t);let e=false;return ()=>{e||(e=true,le.delete(t));}}async function Rr(){let t=[...le];t.length!==0&&await Promise.allSettled(t.map(async e=>{le.delete(e),await R.rm(e,{recursive:true,force:true});}));}function Dr(){if(!(oe.size>0))for(let t of Sr){let e=()=>{et||(et=Rr().finally(()=>{for(let[r,i]of oe)process.off(r,i);oe.clear(),process.exit(1);}));};oe.set(t,e),process.on(t,e);}}Dr();function xr(t,e){let r=String(process.env.STATIC_PUBLISHER_CRAWL_MANIFEST_PATH||"").trim();if(r)return b.resolve(r);let i=e.trim();return i?b.join(b.resolve(i),"crawl-manifest.json"):b.join(b.resolve(t),".crawl-manifest.json")}function st(t){return b.normalize(t).split(b.sep).join("/")}function tt(t,e){let r=b.relative(b.resolve(t),b.resolve(e));return !r||r.startsWith("..")||b.isAbsolute(r)?null:st(r)}async function $r(t,e,r){let i=xr(t.outputDir,e),n;try{n=await R.readFile(i,"utf8");}catch(u){return u.code==="ENOENT"?(r.warn("Deploy rewrite guard disabled because the crawl manifest is missing.",{manifestPath:i,source:"deploy-guard"}),null):(r.warn("Deploy rewrite guard disabled because the crawl manifest could not be read.",{manifestPath:i,error:u instanceof Error?u.message:String(u),source:"deploy-guard"}),null)}let s;try{s=JSON.parse(n);}catch(u){return r.warn("Deploy rewrite guard disabled because the crawl manifest is invalid JSON.",{manifestPath:i,error:u instanceof Error?u.message:String(u),source:"deploy-guard"}),null}let o=new Map,l=new Map,a=0,c=0;for(let[u,m]of Object.entries(s.pages||{})){let p=String(m?.outputPath||"").trim(),d=p?tt(t.outputDir,p):null;if(d){let g=typeof m?.contentType=="string"&&m.contentType?m.contentType:null;g&&l.set(d,g);}!p||m?.rewriteComplete===true||d&&(a++,o.has(d)||o.set(d,{kind:"page",sourceUrl:u,outputPath:b.resolve(p),relativePath:d}));}for(let[u,m]of Object.entries(s.assets||{})){let p=String(m?.outputPath||"").trim(),d=m?.isText===true,g=p?tt(t.outputDir,p):null;if(g){let w=typeof m?.contentType=="string"&&m.contentType?m.contentType:null;w&&l.set(g,w);}!p||!d||m?.rewriteComplete===true||g&&(c++,o.has(g)||o.set(g,{kind:"asset",sourceUrl:u,outputPath:b.resolve(p),relativePath:g}));}return {manifestPath:i,byRelativePath:o,contentTypeByRelativePath:l,pendingPages:a,pendingTextAssets:c}}function Tr(t){return t&&(xe.test(t)?"__uuid__":/^[0-9a-f]{6,}$/i.test(t)?"__hex__":/^[0-9]{8,}$/.test(t)?"__num__":/^(?=.*[a-z])(?=.*\d)[a-z0-9]{8,}$/i.test(t)?"__alnum__":t)}function Se(t){return t.split(/([_:.\-/=?&#]+)/g).map((e,r)=>r%2===1?e:Tr(e)).join("")}function Cr(t){return t.split(/([_:.\-/=?&#]+)/g).map((e,r)=>r%2===1?e:xe.test(e)?"__uuid__":/^[0-9a-f]{6,}$/i.test(e)?"__hex__":/^[0-9]{6,}$/.test(e)?"__num__":/^[a-z0-9_-]{6,}$/i.test(e)?"__id__":e).join("")}function ue(t,e){return Array.isArray(t)?t.map(r=>ue(r,e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([r,i])=>[r,ue(i,r)])):typeof t!="string"?t:e&&Pr.test(e)?Cr(t):xe.test(t)?"__uuid__":/^[0-9a-f]{6,}$/i.test(t)||/^[0-9]{8,}$/.test(t)?Se(t):t}function Er(t){return t.replace(/((?:https?:\/\/[^"'\s>]+|\/)(?:wp-content|wp-includes)\/[^"'\s>?]+)\?ver=[A-Za-z0-9._-]+(?=$|[#"'])/gi,"$1")}function Mr(t,e){let r=e.trim();if((r.startsWith("{")||r.startsWith("[")||r.startsWith('"'))&&t.startsWith("data-"))try{let n=JSON.parse(r);return JSON.stringify(ue(n))}catch{}if(t.startsWith("data-")&&/^[A-Za-z0-9+/=]+$/.test(r))try{let n=Buffer.from(r,"base64").toString("utf8"),s=JSON.parse(n),o=JSON.stringify(ue(s));return Buffer.from(o,"utf8").toString("base64")}catch{}return e}function Ar(t,e){let r=t.toLowerCase();return r==="class"?e.split(/(\s+)/).map((i,n)=>n%2===1?i:Se(i)).join(""):r==="id"||r==="for"||r==="aria-controls"||r==="aria-labelledby"||r==="aria-describedby"||r==="aria-owns"||r==="aria-activedescendant"||r==="name"?Se(e):r==="href"||r==="src"?Er(e):Mr(r,e)}function kr(t){return t.replace(/<([a-z][^\s/>]*)([^<>]*?)>/gi,(e,r,i)=>{if(r.startsWith("/"))return e;let n=i.replace(/\s([:@a-zA-Z_][-:.a-zA-Z0-9_]*?)=(['"])([\s\S]*?)\2/g,(s,o,l,a)=>{let c=Ar(o,a);return ` ${o}=${l}${c}${l}`});return `<${r}${n}>`})}function Pe(t){let e=b.extname(t).toLowerCase();return [".html",".htm",".xml",".xsl",".txt"].includes(e)||["robots.txt","sitemap.xml"].includes(b.basename(t))}function ae(t,e){return [t.replace(/^\/+|\/+$/g,""),e.replace(/^\/+/,"")].filter(Boolean).join("/")}async function Ir(t,e,r,i){let n=new Map,s,o=0;do{o++;let l=await O(`S3 list objects page ${o} for s3://${e}/${r||""}`,3e5,({httpOptions:a})=>t.send(new ListObjectsV2Command({Bucket:e,Prefix:r||void 0,ContinuationToken:s}),a));for(let a of l.Contents||[]){if(!a.Key)continue;let c=(a.ETag||"").replace(/^"|"$/g,"").toLowerCase(),u=Number(a.Size??0);n.set(a.Key,{etag:c,size:u});}s=l.NextContinuationToken,i.debug(`Listed S3 keys page ${o}: ${n.size} keys so far`);}while(s);return n}async function Lr(t,e,r,i){if(i.has(r))return i.get(r)??null;try{let n=await O(`S3 head object ${r}`,3e5,({httpOptions:o})=>t.send(new HeadObjectCommand({Bucket:e,Key:r}),o)),s={etag:(n.ETag||"").replace(/^"|"$/g,"").toLowerCase(),size:Number(n.ContentLength??0)};return i.set(r,s),s}catch{return i.set(r,null),null}}async function Or(t,e,r,i){let n=[...new Set(Array.from(r).filter(Boolean))];if(n.length===0)return i.info("No explicitly tombstoned S3 objects to delete."),[];i.info(`Deleting ${n.length} explicitly tombstoned S3 object(s)\u2026`);for(let s=0;s<n.length;s+=1e3){let o=n.slice(s,s+1e3);if(o.length===0)continue;let l=await O(`S3 delete objects batch ${Math.floor(s/1e3)+1}`,3e5,({httpOptions:a})=>t.send(new DeleteObjectsCommand({Bucket:e,Delete:{Objects:o.map(c=>({Key:c}))}}),a));if(l.Errors&&l.Errors.length>0){let a=l.Errors.map(c=>`${c.Key||"(unknown)"}: ${c.Code||"DeleteFailed"}`);throw new Error(`S3 reported ${a.length} object deletion error(s): ${a.join(", ")}`)}i.info(`Deleted batch of ${o.length} object(s).`);for(let a of o)i.debug(` deleted: ${a}`);}return n}function jr(t){return createHash("md5").update(t).digest("hex")}function rt(t){return createHash("sha256").update(t).digest("hex")}function ve(t){return createHash("sha256").update(kr(t.toString("utf8"))).digest("hex")}async function Fr(t,e,r,i){if(i.has(r))return i.get(r)??null;try{let o=((await O(`S3 head object metadata ${r}`,3e5,({httpOptions:l})=>t.send(new HeadObjectCommand({Bucket:e,Key:r}),l))).Metadata?.[nt]||"").trim().toLowerCase()||null;return i.set(r,o),o}catch{return i.set(r,null),null}}async function _r(t,e,r,i,n){if(i.has(r))return i.get(r)??null;try{let o=((await O(`S3 head object normalized metadata ${r}`,3e5,({httpOptions:l})=>t.send(new HeadObjectCommand({Bucket:e,Key:r}),l))).Metadata?.[it]||"").trim().toLowerCase();if(o)return i.set(r,o),o}catch{return i.set(r,null),null}if(n.has(r)){let s=n.get(r)??null;return i.set(r,s),s}try{let o=await(await O(`S3 get object ${r}`,3e5,({httpOptions:a})=>t.send(new GetObjectCommand({Bucket:e,Key:r}),a))).Body?.transformToByteArray(),l=o?ve(Buffer.from(o)):null;return n.set(r,l),i.set(r,l),l}catch{return n.set(r,null),i.set(r,null),null}}function Ur(t){return t.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"profile"}function Nr(t,e){let r=t,i=Object.entries(e).sort((n,s)=>s[0].length-n[0].length);for(let[n,s]of i)n&&(r=r.split(n).join(s));return r}async function Wr(t,e,r,i){let n=b.join(t,"asset-map.json"),s;try{s=await R.readFile(n,"utf8");}catch(a){if(a.code==="ENOENT")return;throw a}let o=JSON.parse(s);if(!o||typeof o!="object")return;let l=Object.fromEntries(Object.entries(o).map(([a,c])=>{let u=String(c??"");return e.urlRewriteMode==="absolute"&&e.targetOrigin&&r.targetOrigin&&e.targetOrigin!==r.targetOrigin&&(u=u.split(e.targetOrigin).join(r.targetOrigin)),u=Nr(u,i),[a,u]}));await R.writeFile(n,JSON.stringify(l,null,2),"utf8");}async function zr(t,e,r,i,n,s){let o=t.targetOrigin!==e.targetOrigin,l=Object.keys(i).length>0;if(!r||!o&&!l)return {outputDir:t.outputDir,cleanup:async()=>{}};if(o&&t.urlRewriteMode!=="absolute")throw new Error(`Deployment profile "${r}" changes targetOrigin, but the base crawl output must use urlRewriteMode "absolute" for multi-target redeploys.`);let a=b.join(b.dirname(t.outputDir),`.deploy-profile-${Ur(r)}-${Date.now()}`),c=vr(a);n.info(`Preparing deployment profile "${r}" from existing crawl output to ${a}...`);try{if(await R.rm(a,{recursive:!0,force:!0}),s){await R.mkdir(a,{recursive:!0});for(let d of s){let g=b.join(t.outputDir,d),w=b.join(a,d);await R.mkdir(b.dirname(w),{recursive:!0}),await R.copyFile(g,w);}}else await R.cp(t.outputDir,a,{recursive:!0});let u={...t,sourceOrigin:t.targetOrigin,targetOrigin:e.targetOrigin,extraReplacements:i,outputDir:a},m=1;n.info(`Rewriting text files for deployment profile "${r}"...`);let p=await Xe(u,{},{files:s,onStart:({totalFiles:d,workerCount:g})=>{m=g,n.info(`Rewriting ${d} text file(s) for deployment profile "${r}" with ${g} worker(s).`);},onProgress:({index:d,totalFiles:g,changedTextFiles:w,file:C,changed:x})=>{let S=`Rewriting [${d}/${g}] ${C} (${x?"rewrote":"checked"}; ${w} changed so far)`;g<=200||d<=5||d%10===0||d===g?(n.progress(S,{file:C,index:d,totalFiles:g,changed:x,changedTextFiles:w,workerCount:m}),n.info(S)):n.debug(S);}});return await Wr(a,t,e,i),n.info(`Prepared deployment profile "${r}" in ${a} (${p} rewritten text file(s)).`),{outputDir:a,cleanup:async()=>{c(),await R.rm(a,{recursive:!0,force:!0});}}}catch(u){throw n.error(`Failed to prepare deployment profile "${r}" temporary output.`,{tempDir:a,outputDir:t.outputDir,error:u instanceof Error?u.message:String(u),...u instanceof Error&&u.stack?{stack:u.stack}:{}}),await R.rm(a,{recursive:true,force:true}).catch(()=>{}),c(),await n.flush().catch(()=>{}),u}}async function ot(t=process.argv.slice(2)){let e=await re(),r=Ue(t),i=Ne(e,r),n=b.resolve(i.config.logDir||"logs"),s=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"",o=s?b.join(b.resolve(s),"deploy-diff.json"):"",l=new H(n,"deploy.log.jsonl",i.config.logLevel??"info"),a=i.profile?.extraReplacements??{},c=async()=>{};try{let u=await je(e);if(t.includes("--content-sync")&&u?.schemaVersion!==2)throw new Error("Content-sync deployment requires a valid schema-2 targeted deploy plan.");let p=await _e(e);if(p)throw new Error(`Deployment blocked: the crawl started at ${p.startedAt} did not complete its final rewrite. Run a successful crawl or resume the rewrite before deploying.`);let d=await zr(e,i.config,i.name,a,l,u?.schemaVersion===2?u.changedFiles:void 0);c=d.cleanup;let g={...i.config,outputDir:d.outputDir},w=g.s3SyncMode??"sdk-upload-delete";if(u?.schemaVersion===2&&u.deletedFiles.length>0&&w!=="sdk-upload-delete")throw new Error("Content-sync tombstones require the sdk-upload-delete S3 sync mode.");let C=u?.schemaVersion!==2&&d.outputDir!==e.outputDir&&(e.targetOrigin!==i.config.targetOrigin||Object.keys(a).length>0),x=!!u&&!u.fullSyncRequired&&!C;if(u?.schemaVersion===2&&!x)throw new Error("Content-sync deployment cannot widen into a full-output deployment.");i.name&&l.info(`Using deployment profile: ${i.name}`),l.info(`Starting deploy \u2014 s3://${g.s3.bucket}/${g.s3.prefix||""} (region: ${g.s3.region})`),l.info(`S3 sync mode: ${w}`),u&&u.fullSyncRequired?l.info("Deploy plan requests a full sync; scanning the whole output tree."):u&&C?l.info("Ignoring incremental deploy plan because deployment-profile rewrites require a full sync."):x&&l.info(`Using incremental deploy plan: ${u.changedFiles.length} changed file(s), ${u.deletedFiles.length} deleted file(s).`),l.mark("deploy");let _=new S3Client({region:g.s3.region}),S=d.outputDir===e.outputDir?await $r(e,s,l):null,$e=u?.schemaVersion===2?[...u.uploadGroups.assets,...u.uploadGroups.content,...u.uploadGroups.listings,...u.uploadGroups.sitemapLeaves,...u.uploadGroups.sitemapIndexes]:u?.changedFiles??[];if(u?.schemaVersion===2){let h=[...new Set($e)],$=[...new Set(u.changedFiles)];if(h.length!==$.length||$.some(f=>!h.includes(f)))throw new Error("Content-sync deploy-plan upload groups do not cover the exact changed-file set.")}let K=x?(await Promise.all($e.map(async h=>{try{return (await R.stat(b.join(g.outputDir,h))).isFile()?h:null}catch{if(u?.schemaVersion===2)throw new Error(`Content-sync planned upload is missing: ${h}`);return null}}))).filter(h=>h!==null):await Gt(["**/*"],{cwd:g.outputDir,onlyFiles:!0,dot:!0}),I=[],W=[],y=K.filter(h=>{let $=S?.byRelativePath.get(st(h));if(!$)return !0;let f=ae(g.s3.prefix,h);return I.push(h),W.push(f),l.reject($.kind,$.sourceUrl||h,"rewrite not completed; deploy upload blocked","deploy-guard",{file:h,key:f,outputPath:$.outputPath,manifestPath:S?.manifestPath}),!1}),Te=new Set((x?y:K).map(h=>ae(g.s3.prefix,h)));S&&(S.pendingPages>0||S.pendingTextAssets>0)&&l.info(`Deploy rewrite guard loaded ${S.pendingPages} pending page(s) and ${S.pendingTextAssets} pending text asset(s) from crawl manifest.`,{manifestPath:S.manifestPath,pendingPages:S.pendingPages,pendingTextAssets:S.pendingTextAssets,source:"deploy-guard"}),I.length>0&&l.warn(`Deploy rewrite guard blocked ${I.length} file(s) from upload because final crawl rewrite is incomplete.`,{rejected:I.length,manifestPath:S?.manifestPath,source:"deploy-guard"}),x?l.info(`Using ${y.length} eligible planned changed file(s) from deploy plan for upload${I.length>0?` (${I.length} blocked by deploy rewrite guard)`:""}.`):l.info(`Found ${K.length} file(s) in output directory "${g.outputDir}"${I.length>0?`; ${y.length} remain eligible for upload after deploy rewrite guard filtering`:""}.`),l.progress("Deploy preflight: comparing local output with remote S3 state.",{phase:"deploy",mode:w,totalFiles:y.length,scannedFiles:K.length,rejected:I.length,deploymentProfile:i.name||"",s3Bucket:g.s3.bucket,s3Prefix:g.s3.prefix||"",targetedPlan:x,deployGuardEnabled:d.outputDir===e.outputDir});let T=0,v=0,U=0,ce=[],V=[],Q=[],ge=[],N=[],z=new Map,at=new Map,lt=new Map,ut=new Map,ct=new Map;x||(l.info("Listing existing S3 objects to detect unchanged files..."),z=await Ir(_,g.s3.bucket,g.s3.prefix,l),l.info(`Found ${z.size} existing key(s) in S3.`));let gt=async h=>z.has(h)?z.get(h)??null:x?Lr(_,g.s3.bucket,h,at):null;for(let h of y){let $=b.join(g.outputDir,h),f=ae(g.s3.prefix,h),E=S?.contentTypeByRelativePath.get(h),Y=E&&E!=="application/octet-stream"?E:br.lookup(h)||E||"application/octet-stream",pt=Pe(h)?g.s3.htmlCacheControl:g.s3.assetCacheControl,P=T+v+U+1;y.length<=200||P<=5||P%10===0||P===y.length?(l.progress(`Uploading [${P}/${y.length}] ${f} (${Y})`,{file:h,key:f,index:P,totalFiles:y.length,contentType:Y,mode:w}),l.info(`Uploading [${P}/${y.length}] ${f} (${Y})`)):l.debug(`Uploading [${P}/${y.length}] ${f} (${Y})`);try{let M=await R.readFile($),Z=await gt(f),X=null,q=null;if(Z){let pe=M.byteLength;if(Z.size===pe){let te=Z.etag.includes("-");if(Z.etag!==""&&!te){let dt=jr(M);if(Z.etag===dt){v++,y.length<=200||v<=5||v%25===0?(l.progress(`Skipped unchanged [${P}/${y.length}] ${f}`,{file:h,key:f,index:P,totalFiles:y.length,uploaded:T,skipped:v,failed:U,mode:w,reason:"etag-md5-match"}),l.info(`Skipped unchanged [${P}/${y.length}] ${f}`)):l.debug(`Skipped unchanged [${P}/${y.length}] ${f}`),V.push(f);continue}}X=rt(M);let Ce=await Fr(_,g.s3.bucket,f,lt);if(Ce&&Ce===X){v++,y.length<=200||v<=5||v%25===0?(l.progress(`Skipped unchanged [${P}/${y.length}] ${f}`,{file:h,key:f,index:P,totalFiles:y.length,uploaded:T,skipped:v,failed:U,mode:w,reason:"metadata-sha256-match"}),l.info(`Skipped unchanged [${P}/${y.length}] ${f}`)):l.debug(`Skipped unchanged [${P}/${y.length}] ${f}`),V.push(f);continue}}if(Pe(h)){q=ve(M);let te=await _r(_,g.s3.bucket,f,ut,ct);if(te&&te===q){v++,y.length<=200||v<=5||v%25===0?(l.progress(`Skipped semantically unchanged [${P}/${y.length}] ${f}`,{file:h,key:f,index:P,totalFiles:y.length,uploaded:T,skipped:v,failed:U,mode:w,reason:"normalized-html-match"}),l.info(`Skipped semantically unchanged [${P}/${y.length}] ${f}`)):l.debug(`Skipped semantically unchanged [${P}/${y.length}] ${f}`),V.push(f);continue}}}X=X??rt(M),q=q??(Pe(h)?ve(M):null),await O(`S3 upload ${f}`,9e5,({abortController:pe})=>new Upload({client:_,abortController:pe,params:{Bucket:g.s3.bucket,Key:f,Body:M,ContentType:Y,CacheControl:pt,Metadata:{[nt]:X,...q?{[it]:q}:{}}}}).done()),T++,ce.push(f),(T%25===0||T===y.length)&&(l.progress(`Uploaded ${T}/${y.length} file(s)\u2026`,{uploaded:T,skipped:v,failed:U,totalFiles:y.length,mode:w}),l.info(`Uploaded ${T}/${y.length} file(s)\u2026`));}catch(M){U++,Q.push(f),l.error(`Failed to upload ${f}: ${M.message}`,{key:f,error:String(M)});}}if(l.info(`Upload complete: ${T} uploaded, ${v} skipped unchanged, ${W.length} rejected by guard, ${U} failed.`),Q.length>0||W.length>0)throw new Error(`Deployment stopped before deletion because ${Q.length} upload(s) failed and ${W.length} upload(s) were rejected.`);if(w==="sdk-upload-delete"){let h=new Set((u?.deletedFiles??[]).map(f=>ae(g.s3.prefix,f))),$=[...h].filter(f=>!Te.has(f));if(!x&&(N=[...z.keys()].filter(E=>!Te.has(E)).filter(E=>!h.has(E)),N.length>0)){l.warn(`Protected ${N.length} remote-only S3 object(s) from deletion because the crawl did not provide explicit tombstones.`,{protected:N.length,source:"deploy-delete-guard"});for(let E of N)l.debug(` protected remote-only object: ${E}`);}ge=await Or(_,g.s3.bucket,x?$:$.filter(f=>z.has(f)),l);}else l.info("Sync mode is sdk-upload-only \u2014 skipping stale object deletion.");o&&(await R.mkdir(b.dirname(o),{recursive:!0}),await R.writeFile(o,JSON.stringify({generatedAt:new Date().toISOString(),mode:w,summary:{totalFiles:K.length,eligibleFiles:y.length,uploaded:ce.length,skipped:V.length,rejected:W.length,failed:Q.length,deleted:ge.length,protected:N.length,...i.name?{profile:i.name}:{}},uploadedKeys:ce,skippedKeys:V,rejectedKeys:W,failedKeys:Q,deletedKeys:ge,protectedRemoteOnlyKeys:N},null,2),"utf8")),u?.schemaVersion!==2&&await Fe(e),l.endMark("deploy"),await l.flush();}finally{await c().catch(()=>{});}}ot().catch(async t=>{console.error(t);try{let r=(await re().catch(()=>null))?.logDir??"logs",i=new H(r,"deploy.log.jsonl","debug");i.error(`Unhandled error: ${t instanceof Error?t.message:String(t)}`,t instanceof Error?{stack:t.stack}:void 0),await i.flush();}catch{}process.exit(1);});
|
|
6
|
+
`;return t.replace(/<head\b[^>]*>/i,n=>`${n}${i} ${e}`)}function lr(t){let e=Ze(t).trim();return e.startsWith("{")||e.startsWith("[")||e.includes("\\/")||/"@context"|"@type"/.test(e)}function ur(t,e){let r=[...new Set(e)].filter(s=>s.includes("/")&&!/\\+\//.test(s)).map(s=>[s,oe(s)]).filter(([s,o])=>s!==o).sort((s,o)=>o[0].length-s[0].length);if(!r.length)return t;let i=s=>{let o=s;for(let[l,a]of r)o=o.split(l).join(a);return o},n=t.replace(/(<script\b[^>]*\btype=["']application\/(?:ld\+)?json["'][^>]*>)([\s\S]*?)(<\/script>)/gi,(s,o,l,a)=>`${o}${i(l)}${a}`);return n=n.replace(/(<meta\b[^>]*\bcontent=(['"]))([\s\S]*?)(\2[^>]*>)/gi,(s,o,l,a,c)=>lr(a)?`${o}${i(a)}${c}`:s),n}function cr(t,e){if(!e)return null;let r=b.dirname(b.resolve(e)),i=b.resolve(t.outputDir),n=b.relative(r,i).replace(/\\/g,"/");return n?(n.startsWith(".")||(n=`./${n}`),n.endsWith("/")?n:`${n}/`):"./"}function gr(t,e,r){let i=cr(e,r);if(!i)return t;let n=t;for(let s of er){let o=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),l=new RegExp(`(?:\\.{1,}/)+${o}`,"g"),a=new RegExp(`(?<!\\.)/${o}`,"g");n=n.replace(l,`${i}${s}`).replace(a,`${i}${s}`);let c=s.replace(/\//g,"\\/"),u=i.replace(/\//g,"\\/"),m=c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),p=new RegExp(`(?:\\.{1,}\\\\/)+${m}`,"g"),d=new RegExp(`(?:\\.{1,}(?:\\\\/|\\\\))+${m}`,"g"),g=new RegExp(`(?<![\\.\\\\])\\/${m}`,"g");n=n.replace(p,`${u}${c}`).replace(d,`${u}${c}`).replace(g,`${u}${c}`);}return n}function Se(t,e,r){if(t.urlRewriteMode==="absolute")return e;let i=(()=>{try{return new URL(e,t.targetOrigin==="."?"https://relative.invalid":t.targetOrigin)}catch{return null}})(),n=i?i.pathname:Xe(e,t.targetOrigin),s=i?`${i.search}${i.hash}`:"";return t.urlRewriteMode==="root-relative"?`${n}${s}`:`${et(t.outputDir,r,n)}${s}`}function Pe(t,e,r,i,n){ae(t,r,Se(e,i,n));}function pr(t,e,r,i,n){if(!r||r===i)return;ae(t,r,i);let s=Se(e,r,n),o=Se(e,i,n);ae(t,s,o);}function dr(t,e,r,i,n={}){let s=t,o={};Pe(o,e,e.sourceOrigin,e.targetOrigin,i);for(let[a,c]of Object.entries(e.extraReplacements))Pe(o,e,a,c,i);for(let[a,c]of Object.entries(r))Pe(o,e,a,c,i);for(let[a,c]of Object.entries(n)){let u=r[a];!u||u===c||pr(o,e,c,u,i);}let l=Object.entries(o).sort((a,c)=>c[0].length-a[0].length);for(let[a,c]of l)s=sr(s,a,c);return e.urlRewriteMode!=="absolute"&&(s=gr(s,e,i)),s=ur(s,l.map(([,a])=>a)),or(e,s,i)&&(s=ar(s)),s}async function fr(t,e,r,i){let n=b.join(t.outputDir,i),s=b.extname(n).toLowerCase(),o;try{o=await D.readFile(n,"utf8");}catch(c){if(c.code!=="ENOENT")throw c;return {changed:false}}let a=dr(o,t,e,s===".js"||s===".mjs"?void 0:n,r);return a!==o?(await Qe(n,a,"utf8"),{changed:true}):{changed:false}}async function mr(t,e){return await new Promise((r,i)=>{let n=a=>{if(l(),a?.error){i(new Error(a.error));return}r({changed:!!a?.changed});},s=a=>{l(),i(a);},o=a=>{l(),a!==0&&i(new Error(`Rewrite worker exited with code ${a}.`));},l=()=>{t.off("message",n),t.off("error",s),t.off("exit",o);};t.on("message",n),t.on("error",s),t.on("exit",o),t.postMessage({file:e});})}async function rt(t,e,r={}){let n=(r.files?[...new Set(r.files)].map(p=>b.resolve(p)).filter(p=>p.startsWith(b.resolve(t.outputDir))).map(p=>b.relative(t.outputDir,p).replace(/\\/g,"/")).filter(p=>p.length>0):await Qt(["**/*"],{cwd:t.outputDir,onlyFiles:true,dot:true})).filter(p=>p!=="asset-map.json"&&Ye(p)),s=0;if(n.length===0)return 0;let o=Math.max(1,Number(t.rewriteConcurrency||t.assetDownloadConcurrency||1)),l=Math.max(1,Math.min(o,n.length,availableParallelism()));await r.onStart?.({totalFiles:n.length,workerCount:l});let a=0,c=0,u=null;if(l===1){for(let p of n){let d=await fr(t,e,r.previousAssetMap??{},p);d.changed&&(s+=1),c+=1,await r.onProgress?.({index:c,totalFiles:n.length,changedTextFiles:s,file:p,changed:d.changed});}return s}let m=Array.from({length:l},async()=>{let p=new Worker(new URL("./rewrite-worker.js",import.meta.url),{workerData:{config:t,assetMap:e,previousAssetMap:r.previousAssetMap??{}}});try{for(;!u;){let d=a;if(d>=n.length)return;a+=1;let g=n[d],w=await mr(p,g);w.changed&&(s+=1),c+=1,await r.onProgress?.({index:c,totalFiles:n.length,changedTextFiles:s,file:g,changed:w.changed});}}catch(d){throw u=d instanceof Error?d:new Error(String(d)),u}finally{await p.terminate().catch(()=>{});}});return await Promise.all(m),s}var ot="wpsuite-sha256",at="wpsuite-normalized-sha256",Dr=/(?:^|[-_:.])(id|uid|nonce|token|hash|instance)(?:$|[-_:.])/i,Te=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,xr=["SIGINT","SIGTERM"],ce=new Set,le=new Map,nt=null;function $r(t){ce.add(t);let e=false;return ()=>{e||(e=true,ce.delete(t));}}async function Tr(){let t=[...ce];t.length!==0&&await Promise.allSettled(t.map(async e=>{ce.delete(e),await D.rm(e,{recursive:true,force:true});}));}function Er(){if(!(le.size>0))for(let t of xr){let e=()=>{nt||(nt=Tr().finally(()=>{for(let[r,i]of le)process.off(r,i);le.clear(),process.exit(1);}));};le.set(t,e),process.on(t,e);}}Er();function Cr(t,e){let r=String(process.env.STATIC_PUBLISHER_CRAWL_MANIFEST_PATH||"").trim();if(r)return b.resolve(r);let i=e.trim();return i?b.join(b.resolve(i),"crawl-manifest.json"):b.join(b.resolve(t),".crawl-manifest.json")}function lt(t){return b.normalize(t).split(b.sep).join("/")}function it(t,e){let r=b.relative(b.resolve(t),b.resolve(e));return !r||r.startsWith("..")||b.isAbsolute(r)?null:lt(r)}async function kr(t,e,r){let i=Cr(t.outputDir,e),n;try{n=await D.readFile(i,"utf8");}catch(u){return u.code==="ENOENT"?(r.warn("Deploy rewrite guard disabled because the crawl manifest is missing.",{manifestPath:i,source:"deploy-guard"}),null):(r.warn("Deploy rewrite guard disabled because the crawl manifest could not be read.",{manifestPath:i,error:u instanceof Error?u.message:String(u),source:"deploy-guard"}),null)}let s;try{s=JSON.parse(n);}catch(u){return r.warn("Deploy rewrite guard disabled because the crawl manifest is invalid JSON.",{manifestPath:i,error:u instanceof Error?u.message:String(u),source:"deploy-guard"}),null}let o=new Map,l=new Map,a=0,c=0;for(let[u,m]of Object.entries(s.pages||{})){let p=String(m?.outputPath||"").trim(),d=p?it(t.outputDir,p):null;if(d){let g=typeof m?.contentType=="string"&&m.contentType?m.contentType:null;g&&l.set(d,g);}!p||m?.rewriteComplete===true||d&&(a++,o.has(d)||o.set(d,{kind:"page",sourceUrl:u,outputPath:b.resolve(p),relativePath:d}));}for(let[u,m]of Object.entries(s.assets||{})){let p=String(m?.outputPath||"").trim(),d=m?.isText===true,g=p?it(t.outputDir,p):null;if(g){let w=typeof m?.contentType=="string"&&m.contentType?m.contentType:null;w&&l.set(g,w);}!p||!d||m?.rewriteComplete===true||g&&(c++,o.has(g)||o.set(g,{kind:"asset",sourceUrl:u,outputPath:b.resolve(p),relativePath:g}));}return {manifestPath:i,byRelativePath:o,contentTypeByRelativePath:l,pendingPages:a,pendingTextAssets:c}}function Ar(t){return t&&(Te.test(t)?"__uuid__":/^[0-9a-f]{6,}$/i.test(t)?"__hex__":/^[0-9]{8,}$/.test(t)?"__num__":/^(?=.*[a-z])(?=.*\d)[a-z0-9]{8,}$/i.test(t)?"__alnum__":t)}function Re(t){return t.split(/([_:.\-/=?&#]+)/g).map((e,r)=>r%2===1?e:Ar(e)).join("")}function Mr(t){return t.split(/([_:.\-/=?&#]+)/g).map((e,r)=>r%2===1?e:Te.test(e)?"__uuid__":/^[0-9a-f]{6,}$/i.test(e)?"__hex__":/^[0-9]{6,}$/.test(e)?"__num__":/^[a-z0-9_-]{6,}$/i.test(e)?"__id__":e).join("")}function ge(t,e){return Array.isArray(t)?t.map(r=>ge(r,e)):t&&typeof t=="object"?Object.fromEntries(Object.entries(t).map(([r,i])=>[r,ge(i,r)])):typeof t!="string"?t:e&&Dr.test(e)?Mr(t):Te.test(t)?"__uuid__":/^[0-9a-f]{6,}$/i.test(t)||/^[0-9]{8,}$/.test(t)?Re(t):t}function Ir(t){return t.replace(/((?:https?:\/\/[^"'\s>]+|\/)(?:wp-content|wp-includes)\/[^"'\s>?]+)\?ver=[A-Za-z0-9._-]+(?=$|[#"'])/gi,"$1")}function Lr(t,e){let r=e.trim();if((r.startsWith("{")||r.startsWith("[")||r.startsWith('"'))&&t.startsWith("data-"))try{let n=JSON.parse(r);return JSON.stringify(ge(n))}catch{}if(t.startsWith("data-")&&/^[A-Za-z0-9+/=]+$/.test(r))try{let n=Buffer.from(r,"base64").toString("utf8"),s=JSON.parse(n),o=JSON.stringify(ge(s));return Buffer.from(o,"utf8").toString("base64")}catch{}return e}function Or(t,e){let r=t.toLowerCase();return r==="class"?e.split(/(\s+)/).map((i,n)=>n%2===1?i:Re(i)).join(""):r==="id"||r==="for"||r==="aria-controls"||r==="aria-labelledby"||r==="aria-describedby"||r==="aria-owns"||r==="aria-activedescendant"||r==="name"?Re(e):r==="href"||r==="src"?Ir(e):Lr(r,e)}function jr(t){return t.replace(/<([a-z][^\s/>]*)([^<>]*?)>/gi,(e,r,i)=>{if(r.startsWith("/"))return e;let n=i.replace(/\s([:@a-zA-Z_][-:.a-zA-Z0-9_]*?)=(['"])([\s\S]*?)\2/g,(s,o,l,a)=>{let c=Or(o,a);return ` ${o}=${l}${c}${l}`});return `<${r}${n}>`})}function ve(t){let e=b.extname(t).toLowerCase();return [".html",".htm",".xml",".xsl",".txt"].includes(e)||["robots.txt","sitemap.xml"].includes(b.basename(t))}function ue(t,e){return [t.replace(/^\/+|\/+$/g,""),e.replace(/^\/+/,"")].filter(Boolean).join("/")}async function Fr(t,e,r,i){let n=new Map,s,o=0;do{o++;let l=await O(`S3 list objects page ${o} for s3://${e}/${r||""}`,3e5,({httpOptions:a})=>t.send(new ListObjectsV2Command({Bucket:e,Prefix:r||void 0,ContinuationToken:s}),a));for(let a of l.Contents||[]){if(!a.Key)continue;let c=(a.ETag||"").replace(/^"|"$/g,"").toLowerCase(),u=Number(a.Size??0);n.set(a.Key,{etag:c,size:u});}s=l.NextContinuationToken,i.debug(`Listed S3 keys page ${o}: ${n.size} keys so far`);}while(s);return n}async function _r(t,e,r,i){if(i.has(r))return i.get(r)??null;try{let n=await O(`S3 head object ${r}`,3e5,({httpOptions:o})=>t.send(new HeadObjectCommand({Bucket:e,Key:r}),o)),s={etag:(n.ETag||"").replace(/^"|"$/g,"").toLowerCase(),size:Number(n.ContentLength??0)};return i.set(r,s),s}catch{return i.set(r,null),null}}async function Ur(t,e,r,i){let n=[...new Set(Array.from(r).filter(Boolean))];if(n.length===0)return i.info("No explicitly tombstoned S3 objects to delete."),[];i.info(`Deleting ${n.length} explicitly tombstoned S3 object(s)\u2026`);for(let s=0;s<n.length;s+=1e3){let o=n.slice(s,s+1e3);if(o.length===0)continue;let l=await O(`S3 delete objects batch ${Math.floor(s/1e3)+1}`,3e5,({httpOptions:a})=>t.send(new DeleteObjectsCommand({Bucket:e,Delete:{Objects:o.map(c=>({Key:c}))}}),a));if(l.Errors&&l.Errors.length>0){let a=l.Errors.map(c=>`${c.Key||"(unknown)"}: ${c.Code||"DeleteFailed"}`);throw new Error(`S3 reported ${a.length} object deletion error(s): ${a.join(", ")}`)}i.info(`Deleted batch of ${o.length} object(s).`);for(let a of o)i.debug(` deleted: ${a}`);}return n}function Nr(t){return createHash("md5").update(t).digest("hex")}function st(t){return createHash("sha256").update(t).digest("hex")}function De(t){return createHash("sha256").update(jr(t.toString("utf8"))).digest("hex")}async function zr(t,e,r,i){if(i.has(r))return i.get(r)??null;try{let o=((await O(`S3 head object metadata ${r}`,3e5,({httpOptions:l})=>t.send(new HeadObjectCommand({Bucket:e,Key:r}),l))).Metadata?.[ot]||"").trim().toLowerCase()||null;return i.set(r,o),o}catch{return i.set(r,null),null}}async function Wr(t,e,r,i,n){if(i.has(r))return i.get(r)??null;try{let o=((await O(`S3 head object normalized metadata ${r}`,3e5,({httpOptions:l})=>t.send(new HeadObjectCommand({Bucket:e,Key:r}),l))).Metadata?.[at]||"").trim().toLowerCase();if(o)return i.set(r,o),o}catch{return i.set(r,null),null}if(n.has(r)){let s=n.get(r)??null;return i.set(r,s),s}try{let o=await(await O(`S3 get object ${r}`,3e5,({httpOptions:a})=>t.send(new GetObjectCommand({Bucket:e,Key:r}),a))).Body?.transformToByteArray(),l=o?De(Buffer.from(o)):null;return n.set(r,l),i.set(r,l),l}catch{return n.set(r,null),i.set(r,null),null}}function qr(t){return t.replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"profile"}function Br(t,e){let r=t,i=Object.entries(e).sort((n,s)=>s[0].length-n[0].length);for(let[n,s]of i)n&&(r=r.split(n).join(s));return r}async function Gr(t,e,r,i){let n=b.join(t,"asset-map.json"),s;try{s=await D.readFile(n,"utf8");}catch(a){if(a.code==="ENOENT")return;throw a}let o=JSON.parse(s);if(!o||typeof o!="object")return;let l=Object.fromEntries(Object.entries(o).map(([a,c])=>{let u=String(c??"");return e.urlRewriteMode==="absolute"&&e.targetOrigin&&r.targetOrigin&&e.targetOrigin!==r.targetOrigin&&(u=u.split(e.targetOrigin).join(r.targetOrigin)),u=Br(u,i),[a,u]}));await D.writeFile(n,JSON.stringify(l,null,2),"utf8");}async function Hr(t,e,r,i,n,s){let o=t.targetOrigin!==e.targetOrigin,l=Object.keys(i).length>0;if(!r||!o&&!l)return {outputDir:t.outputDir,cleanup:async()=>{}};if(o&&t.urlRewriteMode!=="absolute")throw new Error(`Deployment profile "${r}" changes targetOrigin, but the base crawl output must use urlRewriteMode "absolute" for multi-target redeploys.`);let a=b.join(b.dirname(t.outputDir),`.deploy-profile-${qr(r)}-${Date.now()}`),c=$r(a);n.info(`Preparing deployment profile "${r}" from existing crawl output to ${a}...`);try{if(await D.rm(a,{recursive:!0,force:!0}),s){await D.mkdir(a,{recursive:!0});for(let d of s){let g=b.join(t.outputDir,d),w=b.join(a,d);await D.mkdir(b.dirname(w),{recursive:!0}),await D.copyFile(g,w);}}else await D.cp(t.outputDir,a,{recursive:!0});let u={...t,sourceOrigin:t.targetOrigin,targetOrigin:e.targetOrigin,extraReplacements:i,outputDir:a},m=1;n.info(`Rewriting text files for deployment profile "${r}"...`);let p=await rt(u,{},{files:s,onStart:({totalFiles:d,workerCount:g})=>{m=g,n.info(`Rewriting ${d} text file(s) for deployment profile "${r}" with ${g} worker(s).`);},onProgress:({index:d,totalFiles:g,changedTextFiles:w,file:T,changed:S})=>{let v=`Rewriting [${d}/${g}] ${T} (${S?"rewrote":"checked"}; ${w} changed so far)`;g<=200||d<=5||d%10===0||d===g?(n.progress(v,{file:T,index:d,totalFiles:g,changed:S,changedTextFiles:w,workerCount:m}),n.info(v)):n.debug(v);}});return await Gr(a,t,e,i),n.info(`Prepared deployment profile "${r}" in ${a} (${p} rewritten text file(s)).`),{outputDir:a,cleanup:async()=>{c(),await D.rm(a,{recursive:!0,force:!0});}}}catch(u){throw n.error(`Failed to prepare deployment profile "${r}" temporary output.`,{tempDir:a,outputDir:t.outputDir,error:u instanceof Error?u.message:String(u),...u instanceof Error&&u.stack?{stack:u.stack}:{}}),await D.rm(a,{recursive:true,force:true}).catch(()=>{}),c(),await n.flush().catch(()=>{}),u}}async function ut(t=process.argv.slice(2)){let e=await ne(),r=ze(t),i=We(e,r),n=b.resolve(i.config.logDir||"logs"),s=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"",o=s?b.join(b.resolve(s),"deploy-diff.json"):"",l=new G(n,"deploy.log.jsonl",i.config.logLevel??"info"),a=i.profile?.extraReplacements??{},c=async()=>{};try{let u=await _e(e);if(t.includes("--content-sync")&&u?.schemaVersion!==2)throw new Error("Content-sync deployment requires a valid schema-2 targeted deploy plan.");let p=await Ne(e);if(p)throw new Error(`Deployment blocked: the crawl started at ${p.startedAt} did not complete its final rewrite. Run a successful crawl or resume the rewrite before deploying.`);let d=await Hr(e,i.config,i.name,a,l,u?.schemaVersion===2?u.changedFiles:void 0);c=d.cleanup;let g={...i.config,outputDir:d.outputDir},w=g.s3SyncMode??"sdk-upload-delete";if(u?.schemaVersion===2&&u.deletedFiles.length>0&&w!=="sdk-upload-delete")throw new Error("Content-sync tombstones require the sdk-upload-delete S3 sync mode.");let T=u?.schemaVersion!==2&&d.outputDir!==e.outputDir&&(e.targetOrigin!==i.config.targetOrigin||Object.keys(a).length>0),S=!!u&&!u.fullSyncRequired&&!T;if(u?.schemaVersion===2&&!S)throw new Error("Content-sync deployment cannot widen into a full-output deployment.");i.name&&l.info(`Using deployment profile: ${i.name}`),l.info(`Starting deploy \u2014 s3://${g.s3.bucket}/${g.s3.prefix||""} (region: ${g.s3.region})`),l.info(`S3 sync mode: ${w}`),u&&u.fullSyncRequired?l.info("Deploy plan requests a full sync; scanning the whole output tree."):u&&T?l.info("Ignoring incremental deploy plan because deployment-profile rewrites require a full sync."):S&&l.info(`Using incremental deploy plan: ${u.changedFiles.length} changed file(s), ${u.deletedFiles.length} deleted file(s).`),l.mark("deploy");let _=new S3Client({region:g.s3.region}),v=d.outputDir===e.outputDir?await kr(e,s,l):null,Ee=u?.schemaVersion===2?[...u.uploadGroups.assets,...u.uploadGroups.content,...u.uploadGroups.listings,...u.uploadGroups.sitemapLeaves,...u.uploadGroups.sitemapIndexes]:u?.changedFiles??[];if(u?.schemaVersion===2){let h=[...new Set(Ee)],$=[...new Set(u.changedFiles)];if(h.length!==$.length||$.some(f=>!h.includes(f)))throw new Error("Content-sync deploy-plan upload groups do not cover the exact changed-file set.")}let J=S?(await Promise.all(Ee.map(async h=>{try{return (await D.stat(b.join(g.outputDir,h))).isFile()?h:null}catch{if(u?.schemaVersion===2)throw new Error(`Content-sync planned upload is missing: ${h}`);return null}}))).filter(h=>h!==null):await Qt(["**/*"],{cwd:g.outputDir,onlyFiles:!0,dot:!0}),I=[],z=[],y=J.filter(h=>{let $=v?.byRelativePath.get(lt(h));if(!$)return !0;let f=ue(g.s3.prefix,h);return I.push(h),z.push(f),l.reject($.kind,$.sourceUrl||h,"rewrite not completed; deploy upload blocked","deploy-guard",{file:h,key:f,outputPath:$.outputPath,manifestPath:v?.manifestPath}),!1}),Ce=new Set((S?y:J).map(h=>ue(g.s3.prefix,h)));v&&(v.pendingPages>0||v.pendingTextAssets>0)&&l.info(`Deploy rewrite guard loaded ${v.pendingPages} pending page(s) and ${v.pendingTextAssets} pending text asset(s) from crawl manifest.`,{manifestPath:v.manifestPath,pendingPages:v.pendingPages,pendingTextAssets:v.pendingTextAssets,source:"deploy-guard"}),I.length>0&&l.warn(`Deploy rewrite guard blocked ${I.length} file(s) from upload because final crawl rewrite is incomplete.`,{rejected:I.length,manifestPath:v?.manifestPath,source:"deploy-guard"}),S?l.info(`Using ${y.length} eligible planned changed file(s) from deploy plan for upload${I.length>0?` (${I.length} blocked by deploy rewrite guard)`:""}.`):l.info(`Found ${J.length} file(s) in output directory "${g.outputDir}"${I.length>0?`; ${y.length} remain eligible for upload after deploy rewrite guard filtering`:""}.`),l.progress("Deploy preflight: comparing local output with remote S3 state.",{phase:"deploy",mode:w,totalFiles:y.length,scannedFiles:J.length,rejected:I.length,deploymentProfile:i.name||"",s3Bucket:g.s3.bucket,s3Prefix:g.s3.prefix||"",targetedPlan:S,deployGuardEnabled:d.outputDir===e.outputDir});let E=0,R=0,U=0,pe=[],V=[],Q=[],de=[],N=[],W=new Map,ct=new Map,gt=new Map,pt=new Map,dt=new Map;S||(l.info("Listing existing S3 objects to detect unchanged files..."),W=await Fr(_,g.s3.bucket,g.s3.prefix,l),l.info(`Found ${W.size} existing key(s) in S3.`));let ft=async h=>W.has(h)?W.get(h)??null:S?_r(_,g.s3.bucket,h,ct):null;for(let h of y){let $=b.join(g.outputDir,h),f=ue(g.s3.prefix,h),C=v?.contentTypeByRelativePath.get(h),Y=C&&C!=="application/octet-stream"?C:Rr.lookup(h)||C||"application/octet-stream",mt=ve(h)?g.s3.htmlCacheControl:g.s3.assetCacheControl,P=E+R+U+1;y.length<=200||P<=5||P%10===0||P===y.length?(l.progress(`Uploading [${P}/${y.length}] ${f} (${Y})`,{file:h,key:f,index:P,totalFiles:y.length,contentType:Y,mode:w}),l.info(`Uploading [${P}/${y.length}] ${f} (${Y})`)):l.debug(`Uploading [${P}/${y.length}] ${f} (${Y})`);try{let k=await D.readFile($),Z=await ft(f),X=null,q=null;if(Z){let fe=k.byteLength;if(Z.size===fe){let re=Z.etag.includes("-");if(Z.etag!==""&&!re){let ht=Nr(k);if(Z.etag===ht){R++,y.length<=200||R<=5||R%25===0?(l.progress(`Skipped unchanged [${P}/${y.length}] ${f}`,{file:h,key:f,index:P,totalFiles:y.length,uploaded:E,skipped:R,failed:U,mode:w,reason:"etag-md5-match"}),l.info(`Skipped unchanged [${P}/${y.length}] ${f}`)):l.debug(`Skipped unchanged [${P}/${y.length}] ${f}`),V.push(f);continue}}X=st(k);let ke=await zr(_,g.s3.bucket,f,gt);if(ke&&ke===X){R++,y.length<=200||R<=5||R%25===0?(l.progress(`Skipped unchanged [${P}/${y.length}] ${f}`,{file:h,key:f,index:P,totalFiles:y.length,uploaded:E,skipped:R,failed:U,mode:w,reason:"metadata-sha256-match"}),l.info(`Skipped unchanged [${P}/${y.length}] ${f}`)):l.debug(`Skipped unchanged [${P}/${y.length}] ${f}`),V.push(f);continue}}if(ve(h)){q=De(k);let re=await Wr(_,g.s3.bucket,f,pt,dt);if(re&&re===q){R++,y.length<=200||R<=5||R%25===0?(l.progress(`Skipped semantically unchanged [${P}/${y.length}] ${f}`,{file:h,key:f,index:P,totalFiles:y.length,uploaded:E,skipped:R,failed:U,mode:w,reason:"normalized-html-match"}),l.info(`Skipped semantically unchanged [${P}/${y.length}] ${f}`)):l.debug(`Skipped semantically unchanged [${P}/${y.length}] ${f}`),V.push(f);continue}}}X=X??st(k),q=q??(ve(h)?De(k):null),await O(`S3 upload ${f}`,9e5,({abortController:fe})=>new Upload({client:_,abortController:fe,params:{Bucket:g.s3.bucket,Key:f,Body:k,ContentType:Y,CacheControl:mt,Metadata:{[ot]:X,...q?{[at]:q}:{}}}}).done()),E++,pe.push(f),(E%25===0||E===y.length)&&(l.progress(`Uploaded ${E}/${y.length} file(s)\u2026`,{uploaded:E,skipped:R,failed:U,totalFiles:y.length,mode:w}),l.info(`Uploaded ${E}/${y.length} file(s)\u2026`));}catch(k){U++,Q.push(f),l.error(`Failed to upload ${f}: ${k.message}`,{key:f,error:String(k)});}}if(l.info(`Upload complete: ${E} uploaded, ${R} skipped unchanged, ${z.length} rejected by guard, ${U} failed.`),Q.length>0||z.length>0)throw new Error(`Deployment stopped before deletion because ${Q.length} upload(s) failed and ${z.length} upload(s) were rejected.`);if(w==="sdk-upload-delete"){let h=new Set((u?.deletedFiles??[]).map(f=>ue(g.s3.prefix,f))),$=[...h].filter(f=>!Ce.has(f));if(!S&&(N=[...W.keys()].filter(C=>!Ce.has(C)).filter(C=>!h.has(C)),N.length>0)){l.warn(`Protected ${N.length} remote-only S3 object(s) from deletion because the crawl did not provide explicit tombstones.`,{protected:N.length,source:"deploy-delete-guard"});for(let C of N)l.debug(` protected remote-only object: ${C}`);}de=await Ur(_,g.s3.bucket,S?$:$.filter(f=>W.has(f)),l);}else l.info("Sync mode is sdk-upload-only \u2014 skipping stale object deletion.");o&&(await D.mkdir(b.dirname(o),{recursive:!0}),await D.writeFile(o,JSON.stringify({generatedAt:new Date().toISOString(),mode:w,summary:{totalFiles:J.length,eligibleFiles:y.length,uploaded:pe.length,skipped:V.length,rejected:z.length,failed:Q.length,deleted:de.length,protected:N.length,...i.name?{profile:i.name}:{}},uploadedKeys:pe,skippedKeys:V,rejectedKeys:z,failedKeys:Q,deletedKeys:de,protectedRemoteOnlyKeys:N},null,2),"utf8")),u?.schemaVersion!==2&&await Ue(e),l.endMark("deploy"),await l.flush();}finally{await c().catch(()=>{});}}ut().catch(async t=>{console.error(t);try{let r=(await ne().catch(()=>null))?.logDir??"logs",i=new G(r,"deploy.log.jsonl","debug");i.error(`Unhandled error: ${t instanceof Error?t.message:String(t)}`,t instanceof Error?{stack:t.stack}:void 0),await i.flush();}catch{}process.exit(1);});
|
package/dist/invalidate.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import b from'fs/promises';import Q from'http';import Y from'https';import f from'path';import {CloudFrontClient,waitUntilInvalidationCompleted,CreateInvalidationCommand}from'@aws-sdk/client-cloudfront';function F(r){let e=r.trim();return e==="."?".":e.replace(/\/$/,"")}function K(r){let e=String(r??"").trim();if(!e)return "";let t=e;if(/^https?:\/\//i.test(t))try{t=new URL(t).pathname;}catch{return ""}if(t=t.split(/[?#]/,1)[0]?.replace(/\\/g,"/").trim()??"",!t)return "";let n=t.endsWith("/"),i=t.replace(/^\/+/,"").split("/").map(s=>s.replace(/[^A-Za-z0-9._-]/g,"")).filter(s=>s.length>0&&s!=="."&&s!=="..");if(i.length===0)return "";let o=`/${i.join("/")}`;return n&&f.extname(o)===""&&(o+="/"),o==="/"?"":o}function T(r){return !r||typeof r!="object"?{}:Object.fromEntries(Object.entries(r).map(([e,t])=>[e.trim(),String(t??"")]).filter(([e])=>e.length>0))}function Z(r){if(!r||typeof r!="object")return {};let e={};for(let[t,n]of Object.entries(r)){let i=t.trim();if(!i||!n||typeof n!="object")continue;let o=n,s={};if(typeof o.targetOrigin=="string"){let a=F(o.targetOrigin);a&&(s.targetOrigin=a);}let u=T(o.extraReplacements);if(Object.keys(u).length>0&&(s.extraReplacements=u),o.s3&&typeof o.s3=="object"){let a={},l=o.s3;typeof l.bucket=="string"&&(a.bucket=l.bucket.trim()),typeof l.prefix=="string"&&(a.prefix=l.prefix.trim()),typeof l.region=="string"&&(a.region=l.region.trim()),typeof l.htmlCacheControl=="string"&&(a.htmlCacheControl=l.htmlCacheControl.trim()),typeof l.assetCacheControl=="string"&&(a.assetCacheControl=l.assetCacheControl.trim()),Object.keys(a).length>0&&(s.s3=a);}if(o.cloudFront&&typeof o.cloudFront=="object"){let a={},l=o.cloudFront;typeof l.distributionId=="string"&&(a.distributionId=l.distributionId.trim()),Array.isArray(l.invalidationPaths)&&(a.invalidationPaths=l.invalidationPaths.map(c=>String(c??"").trim()).filter(c=>c.length>0)),Object.keys(a).length>0&&(s.cloudFront=a);}e[i]=s;}return e}function A(r){return r==="PROFESSIONAL"||r==="AGENCY"?r:void 0}function X(r,e){if(!r||typeof r!="object")return null;let t=r,n=t.command;if(n!=="publish"&&n!=="crawl"&&n!=="deploy"&&n!=="invalidate"&&n!=="retry-timeouts"&&n!=="url"&&n!=="content-sync")return null;let i=Number.parseInt(String(t.intervalMinutes??"0"),10);if(!Number.isFinite(i)||i<1)return null;let o=String(t.id??`${n}-${e+1}`).trim();if(!o)return null;let s=String(t.deploymentProfile??"").trim(),u=String(t.url??"").trim(),a=Array.isArray(t.postTypes)?[...new Set(t.postTypes.map(c=>String(c??"").trim().toLowerCase().replace(/[^a-z0-9_-]/g,"")).filter(Boolean))]:[],l=Array.isArray(t.listingPaths)?[...new Set(t.listingPaths.map(c=>String(c??"").trim()).filter(Boolean))]:[];return n==="content-sync"&&a.length===0?null:{id:o,enabled:t.enabled!==false,command:n,intervalMinutes:i,...n==="publish"||n==="crawl"?{crawlMode:t.crawlMode==="incremental"?"incremental":"full"}:{},...(n==="publish"||n==="deploy"||n==="invalidate"||n==="content-sync")&&s?{deploymentProfile:s}:{},...u?{url:u}:{},...a.length>0?{postTypes:a}:{},...l.length>0?{listingPaths:l}:{},...typeof t.includePostTypeArchives=="boolean"?{includePostTypeArchives:t.includePostTypeArchives}:{},...typeof t.includeTaxonomyArchives=="boolean"?{includeTaxonomyArchives:t.includeTaxonomyArchives}:{},...typeof t.includeAuthorArchives=="boolean"?{includeAuthorArchives:t.includeAuthorArchives}:{},...typeof t.includeDateArchives=="boolean"?{includeDateArchives:t.includeDateArchives}:{},...typeof t.includePostsPage=="boolean"?{includePostsPage:t.includePostsPage}:{},...typeof t.includeSitemapChain=="boolean"?{includeSitemapChain:t.includeSitemapChain}:{}}}function O(r){let e=r&&typeof r=="object"?r:{},t=Array.isArray(e.rules)?e.rules.map((n,i)=>X(n,i)).filter(n=>!!n):[];return {enabled:e.enabled===true,timezone:typeof e.timezone=="string"&&e.timezone.trim()!==""?e.timezone.trim():"UTC",rules:t}}function ee(r){if(!r||typeof r!="object")return;let e=r,t={};for(let i of ["accountId","siteId"]){let o=e[i];typeof o=="string"&&o.trim()!==""&&(t[i]=o.trim());}let n=Number(e.lastUpdate??0);return Number.isFinite(n)&&n>0&&(t.lastUpdate=Math.floor(n)),e.subscriber===true&&(t.subscriber=true),Object.keys(t).length>0?t:void 0}function E(r){let e=r&&typeof r=="object"?r:{},t=String(e.accountId??"").trim(),n=String(e.siteId??"").trim(),i=e.subscriber===true,o=ee(e.siteSettings),s={...o??{},...t?{accountId:o?.accountId??t}:{},...n?{siteId:o?.siteId??n}:{},...o?.subscriber===true||i?{subscriber:true}:{}},u={},a=String(e.apiBase??"").trim();a&&(u.apiBase=a);let l=String(e.runtimeToken??e.nonce??"").trim();l&&(u.runtimeToken=l);let c=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();c&&(u.virtualAssetBaseUrl=c),Object.keys(s).length>0&&(u.siteSettings=s);let d=A(e.subscriptionType);return d&&(u.subscriptionType=d),u}function te(r){try{let e=new URL(r);globalThis.location=e;}catch{}}function N(r){return typeof r=="string"?r:r instanceof URL?r.toString():r.url}function re(r,e){let t=new Headers(r instanceof Request?r.headers:void 0);if(e?.headers)for(let[n,i]of new Headers(e.headers).entries())t.set(n,i);return t}async function U(r,e,t=5){let n=new URL(N(r)),i=String(e?.method??(r instanceof Request?r.method:"GET")).toUpperCase(),o=n.protocol==="http:"?Q:Y,s=re(r,e);return await new Promise((u,a)=>{let l=o.request(n,{method:i,headers:Object.fromEntries(s.entries()),...n.protocol==="https:"?{rejectUnauthorized:false}:{}},c=>{let d=[];c.on("data",p=>{d.push(Buffer.isBuffer(p)?p:Buffer.from(p));}),c.on("error",a),c.on("end",()=>{let p=c.statusCode??0,g=c.headers.location;if(t>0&&g&&[301,302,303,307,308].includes(p)){u(U(new URL(g,n),{method:p===303?"GET":i},t-1));return}let m=new Headers;for(let[h,w]of Object.entries(c.headers))Array.isArray(w)?m.set(h,w.join(", ")):typeof w=="string"&&m.set(h,w);u(new Response(Buffer.concat(d),{status:p,statusText:c.statusMessage??"",headers:m}));});});l.on("error",a),l.end();})}function ie(r){let e=E(r.wpsuite),t={...e.siteSettings??{},...e.siteSettings?.subscriber===true||e.subscriptionType==="PROFESSIONAL"||e.subscriptionType==="AGENCY"?{subscriber:true}:{}},n=String(t.accountId??"").trim(),i=String(t.siteId??"").trim(),o=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();if(r.wpsuite={...e.apiBase?{apiBase:e.apiBase}:{},...e.runtimeToken?{runtimeToken:e.runtimeToken}:{},...o?{virtualAssetBaseUrl:o}:{},...Object.keys(t).length>0?{siteSettings:t}:{},...e.subscriptionType?{subscriptionType:e.subscriptionType}:{}},!n||!i||!o)return false;te(r.sourceOrigin);let s=globalThis,a={...s.WpSuite??{},siteSettings:t,uploadUrl:o};return e.apiBase&&(a.apiBase=e.apiBase),s.WpSuite=a,true}async function ne(r){let e=String(r.wpsuite?.virtualAssetBaseUrl??r.wpsuite?.uploadUrl??"").trim();if(!ie(r)){let i=r.wpsuite?.siteSettings,o=[String(i?.accountId??"").trim()?"":"accountId",String(i?.siteId??"").trim()?"":"siteId",e?"":"virtualAssetBaseUrl"].filter(Boolean);return {remote:null,diagnostic:{status:"invalid-runtime",virtualAssetBaseUrl:e,subscriptionType:null,error:`Missing WP Suite runtime field(s): ${o.join(", ")}.`,requests:[]}}}let t=globalThis.fetch,n=[];try{typeof t=="function"&&/^https?:\/\//i.test(e)&&(globalThis.fetch=(async(a,l)=>{let c=N(a);if(c.startsWith(e)){let d=(()=>{try{return new URL(c).pathname}catch{return c}})();try{let p=r.ignoreHttpsErrors&&c.startsWith("https://")?await U(a,l):await t(a,l);return n.push({path:d,status:p.status,ok:p.ok,error:null}),p}catch(p){throw n.push({path:d,status:null,ok:!1,error:p instanceof Error?p.message:String(p)}),p}}return t(a,l)}));let{getConfig:i}=await import('@smart-cloud/wpsuite-core'),o=await i("publisher"),s=o&&typeof o=="object"?o:null,u=A(s?.subscriptionType);return {remote:s,diagnostic:{status:s?"loaded":"unavailable",virtualAssetBaseUrl:e,subscriptionType:u??null,error:s?null:"WP Suite publisher config loader returned no configuration.",requests:n}}}catch(i){return {remote:null,diagnostic:{status:"unavailable",virtualAssetBaseUrl:e,subscriptionType:null,error:i instanceof Error?i.message:String(i),requests:n}}}finally{typeof t=="function"&&(globalThis.fetch=t);}}function oe(r,e){let t=Z(e?.deploymentProfiles),n=String(e?.defaultDeploymentProfile??"").trim(),i=t[n]?n:"",o=A(e?.subscriptionType),s=E(r.wpsuite);return {...r,scheduler:O(e?.scheduler),deploymentProfiles:t,defaultDeploymentProfile:i,...o?{subscriptionType:o}:{},wpsuite:{...s,...s.siteSettings||o?{siteSettings:{...s.siteSettings??{},...s.siteSettings?.subscriber===true||o==="PROFESSIONAL"||o==="AGENCY"?{subscriber:true}:{}}}:{},...o?{subscriptionType:o}:{}}}}function R(r,e){let n=String(r||"").replace(/\\/g,"/").trim().replace(/^\/+|\/+$/g,"");if(!n)return e;let i=n.split("/").map(o=>o.trim()).filter(o=>o.length>0&&o!=="."&&o!=="..");return i.length>0?i.join("/"):e}function se(){let r=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return r.trim()?f.resolve(r):""}function x(r,e,t){let n=String(e||"").trim();return n&&f.isAbsolute(n)?f.resolve(n):f.resolve(r,R(n,t))}async function I(r,e={}){let t=String("").trim()||process.env.PUBLISHER_CONFIG||"publisher.config.json",n=await b.readFile(t,"utf8"),i=JSON.parse(n);i.sourceOrigin=i.sourceOrigin.replace(/\/$/,""),i.targetOrigin=F(i.targetOrigin),i.ignoreHttpsErrors??=false,i.outputDir=String(i.outputDir||"export").trim()||"export",i.urlRewriteMode||=i.targetOrigin==="."?"relative":"absolute",i.noJavaScriptRenderPathPrefixes||=[],i.seedPaths||=[],i.generated404RequestPath=K(i.generated404RequestPath),i.sitemapPaths||=["/sitemap_index.xml","/sitemap.xml"],i.allowedAssetHosts||=[],i.assetPathPrefixes||=["/wp-content/","/wp-includes/","/static/","/assets/","/build/","/_next/","/docs/","/sitemap","/robots.txt","/llms.txt"],i.blockedPathPrefixes||=[],i.blockedSearchFragments||=[],i.concurrency||=1,i.maxPages||=0,i.extraReplacements=T(i.extraReplacements),i.postCrawlCopyMap=T(i.postCrawlCopyMap),i.logDir=String(i.logDir||"logs").trim()||"logs",i.verbose??=false,i.logLevel||=i.verbose?"debug":"info",i.s3SyncMode||="sdk-upload-delete",i.readiness||={waitForSelector:null,waitForFunction:null,timeoutMs:1500,fallbackWaitMs:1500},i.readiness.timeoutMs??=1500,i.readiness.fallbackWaitMs??=1500,i.viewport||={width:1440,height:1200},i.navigationTimeoutMs||=3e4,i.assetDownloadConcurrency=Number(i.assetDownloadConcurrency)>0?Number(i.assetDownloadConcurrency):i.concurrency,i.rewriteConcurrency=Number(i.rewriteConcurrency)>0?Number(i.rewriteConcurrency):i.assetDownloadConcurrency,i.wpsuite=E(i.wpsuite),i.scheduler=O(void 0),i.deploymentProfiles={},i.defaultDeploymentProfile="",i.deploymentTargetOverride=String(i.deploymentTargetOverride??"").trim();let o=await ne(i);e.onRemotePublisherConfigDiagnostic?.(o.diagnostic);let s=oe(i,o.remote),u=se(),a=u?f.resolve(u,".."):"";return a?(s.outputDir=x(a,s.outputDir,"export"),s.logDir=x(a,s.logDir,"logs")):(f.isAbsolute(s.outputDir)||(s.outputDir=R(s.outputDir,"export")),f.isAbsolute(s.logDir)||(s.logDir=R(s.logDir,"logs"))),s}function ae(r){let e=r/6e4;if(Number.isInteger(e)&&e>=1)return `${e} minute${"s"}`;let t=Math.ceil(r/1e3);return `${t} second${t===1?"":"s"}`}async function L(r,e,t){let n=new AbortController,i=globalThis.setTimeout(()=>{n.abort(new Error(`${r} timed out after ${ae(e)}.`));},e);try{return await t({abortController:n,httpOptions:{abortSignal:n.signal,requestTimeout:e}})}finally{globalThis.clearTimeout(i);}}var ue=".deploy-plan.json",ce="deploy-plan.json";function pe(){let r=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return r.trim()?f.resolve(r):""}function ge(r){let e=String(r||"").replace(/\\/g,"/").replace(/^\/+/,"").trim(),t=f.posix.normalize(e);return !e||!t||t==="."||/^[a-zA-Z]:/.test(t)||t.startsWith("../")||t===".."?null:t}function de(r){let e=String(r||"").trim();if(!e.startsWith("/")||e.startsWith("//")||e.includes("*")||e.includes("#"))return null;try{let t=new URL(e,"https://content-sync.invalid");return t.origin!=="https://content-sync.invalid"?null:`${f.posix.normalize(t.pathname)}${t.search}`}catch{return null}}function P(r){return [...new Set(r.map(ge).filter(e=>e!==null))]}function me(r,e){let t={generatedAt:String(e.generatedAt||new Date().toISOString()),outputDir:f.resolve(r.outputDir),runMode:e.runMode,crawlMode:e.crawlMode,fullSyncRequired:!!e.fullSyncRequired,changedFiles:P(e.changedFiles||[]),deletedFiles:P(e.deletedFiles||[]),rewriteTargets:P(e.rewriteTargets||[])};return e.schemaVersion===2?{...t,schemaVersion:2,runMode:"content-sync",crawlMode:"incremental",fullSyncRequired:false,consumerId:String(e.consumerId||"").trim(),fromSequence:Math.max(0,Number(e.fromSequence)||0),toSequence:Math.max(0,Number(e.toSequence)||0),impactHash:String(e.impactHash||"").trim(),uploadGroups:{assets:P(e.uploadGroups?.assets||[]),content:P(e.uploadGroups?.content||[]),listings:P(e.uploadGroups?.listings||[]),sitemapLeaves:P(e.uploadGroups?.sitemapLeaves||[]),sitemapIndexes:P(e.uploadGroups?.sitemapIndexes||[])},invalidationPaths:[...new Set((e.invalidationPaths||[]).map(de).filter(n=>n!==null))].sort()}:{schemaVersion:1,...t,runMode:e.runMode}}function he(r){if(!r||typeof r!="object")return false;let e=r;if(e.schemaVersion===2){let t=e;return t.runMode==="content-sync"&&t.crawlMode==="incremental"&&t.fullSyncRequired===false&&typeof t.generatedAt=="string"&&typeof t.outputDir=="string"&&typeof t.consumerId=="string"&&t.consumerId.trim()!==""&&Number.isSafeInteger(t.fromSequence)&&Number.isSafeInteger(t.toSequence)&&Number(t.toSequence)>=Number(t.fromSequence)&&typeof t.impactHash=="string"&&/^[a-f0-9]{64}$/.test(t.impactHash)&&Array.isArray(t.changedFiles)&&Array.isArray(t.deletedFiles)&&Array.isArray(t.rewriteTargets)&&!!t.uploadGroups&&Array.isArray(t.uploadGroups.assets)&&Array.isArray(t.uploadGroups.content)&&Array.isArray(t.uploadGroups.listings)&&Array.isArray(t.uploadGroups.sitemapLeaves)&&Array.isArray(t.uploadGroups.sitemapIndexes)&&Array.isArray(t.invalidationPaths)}return e.schemaVersion===1&&typeof e.generatedAt=="string"&&typeof e.outputDir=="string"&&(e.runMode==="full"||e.runMode==="retry-timeouts"||e.runMode==="single-url")&&(e.crawlMode==="full"||e.crawlMode==="incremental")&&typeof e.fullSyncRequired=="boolean"&&Array.isArray(e.changedFiles)&&Array.isArray(e.deletedFiles)&&Array.isArray(e.rewriteTargets)}function fe(r){let e=f.join(f.resolve(r.outputDir),ue),t=pe();return t?[f.join(t,ce),e]:[e]}async function j(r){let e=f.resolve(r.outputDir);for(let t of fe(r))try{let n=await b.readFile(t,"utf8"),i=JSON.parse(n);if(!he(i)||f.resolve(i.outputDir)!==e)continue;return me(r,i)}catch{}return null}function ye(r){return typeof r.subscriptionType=="string"&&r.subscriptionType.trim()!==""}function q(r){let e="";for(let n=0;n<r.length;n++){let i=r[n];if(i==="--profile"){let o=(r[n+1]||"").trim();if(!o)throw new Error("Missing value for --profile.");e=o,n+=1;}else if(i.startsWith("--profile=")){let o=i.slice(10).trim();if(!o)throw new Error("Missing value for --profile.");e=o;}}let t=String(process.env.PUBLISHER_DEPLOY_PROFILE||process.env.PUBLISHER_DEPLOYMENT_PROFILE||"").trim();return e||t||null}function Pe(r,e){return {...r,...e??{}}}function be(r,e){return {...r,...e??{},invalidationPaths:[...(e?.invalidationPaths??r.invalidationPaths)||[]]}}function _(r,e){let t=String(e??r.deploymentTargetOverride??"").trim();if(!ye(r)){if(t)throw new Error(`Deployment target "${t}" requires an active WPSuite subscription and remote publisher config.`);return {name:null,profile:null,config:r}}let n=String(t||r.defaultDeploymentProfile||"").trim();if(!n)return {name:null,profile:null,config:r};let i=r.deploymentProfiles?.[n];if(!i)throw new Error(`Unknown deployment profile "${n}". Check the linked WPSuite publisher configuration.`);return {name:n,profile:i,config:{...r,targetOrigin:i.targetOrigin??r.targetOrigin,s3:Pe(r.s3,i.s3),cloudFront:be(r.cloudFront,i.cloudFront)}}}var $={error:0,warn:1,info:2,debug:3},W=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"",C=W?f.join(W,"current-progress.json"):"",B=Promise.resolve();function H(r){return r.includes("crawl")?"crawl":r.includes("deploy")?"deploy":r.includes("invalidate")?"invalidate":r}function we(r,e){let t={...r},n=new Set(["pagesQueued","pagesRendered","assetsQueued","sitemapsQueued","pagesDiscovered","assetsDiscovered","sitemapsDiscovered","pagesSaved","assetsSaved","donePages","doneAssets","doneSitemaps","changedTextFiles","uploaded","failed","index","totalFiles","pageQueue","assetQueue","sitemapQueue"]);for(let[i,o]of Object.entries(e)){let s=t[i];if(typeof s=="number"&&typeof o=="number"&&n.has(i)){t[i]=Math.max(s,o);continue}t[i]=o;}return t}function ve(r,e,t){C&&(B=B.then(async()=>{let n=new Date,i=n.toISOString();await b.mkdir(f.dirname(C),{recursive:true});let o=await b.readFile(C,"utf8").then(h=>JSON.parse(h)).catch(()=>null),s=o&&typeof o.details=="object"&&o.details?o.details:{},u=H(r),a=o?.currentStep||H(o?.source||""),l=o?.startedAt||i,c={...o?.stepDurationsSec??{}},d=o?.stepStartedAt||i;if(a&&a!==u&&o?.stepStartedAt){let h=Math.max(0,Math.round((n.getTime()-new Date(o.stepStartedAt).getTime())/1e3));c[a]=(c[a]??0)+h,d=i;}let p=Math.max(0,Math.round((n.getTime()-new Date(d).getTime())/1e3)),g=Math.max(0,Math.round((n.getTime()-new Date(l).getTime())/1e3)),m={checkedAt:i,source:r,message:e,details:we(s,t??{}),startedAt:l,currentStep:u,stepStartedAt:d,stepElapsedSec:p,totalElapsedSec:g,stepDurationsSec:c};await b.writeFile(C,JSON.stringify(m,null,2),"utf8");}).catch(()=>{}));}async function Se(r,e){await b.mkdir(f.dirname(r),{recursive:true}),await b.appendFile(r,`${JSON.stringify(e)}
|
|
2
|
-
`,"utf8");}var
|
|
3
|
-
`,"utf8");});}enqueueJsonLine(e,t){this.enqueueTask(()=>
|
|
1
|
+
import b from'fs/promises';import X from'http';import ee from'https';import h from'path';import {CloudFrontClient,waitUntilInvalidationCompleted,CreateInvalidationCommand}from'@aws-sdk/client-cloudfront';function j(r){let e=r.trim();return e==="."?".":e.replace(/\/$/,"")}function te(r){let e=String(r??"").trim();if(!e)return "";let t=e;if(/^https?:\/\//i.test(t))try{t=new URL(t).pathname;}catch{return ""}if(t=t.split(/[?#]/,1)[0]?.replace(/\\/g,"/").trim()??"",!t)return "";let n=t.endsWith("/"),i=t.replace(/^\/+/,"").split("/").map(o=>o.replace(/[^A-Za-z0-9._-]/g,"")).filter(o=>o.length>0&&o!=="."&&o!=="..");if(i.length===0)return "";let s=`/${i.join("/")}`;return n&&h.extname(s)===""&&(s+="/"),s==="/"?"":s}function k(r){return !r||typeof r!="object"?{}:Object.fromEntries(Object.entries(r).map(([e,t])=>[e.trim(),String(t??"")]).filter(([e])=>e.length>0))}function re(r){if(!r||typeof r!="object")return {};let e={};for(let[t,n]of Object.entries(r)){let i=t.trim();if(!i||!n||typeof n!="object")continue;let s=n,o={};if(typeof s.targetOrigin=="string"){let a=j(s.targetOrigin);a&&(o.targetOrigin=a);}let u=k(s.extraReplacements);if(Object.keys(u).length>0&&(o.extraReplacements=u),s.s3&&typeof s.s3=="object"){let a={},l=s.s3;typeof l.bucket=="string"&&(a.bucket=l.bucket.trim()),typeof l.prefix=="string"&&(a.prefix=l.prefix.trim()),typeof l.region=="string"&&(a.region=l.region.trim()),typeof l.htmlCacheControl=="string"&&(a.htmlCacheControl=l.htmlCacheControl.trim()),typeof l.assetCacheControl=="string"&&(a.assetCacheControl=l.assetCacheControl.trim()),Object.keys(a).length>0&&(o.s3=a);}if(s.cloudFront&&typeof s.cloudFront=="object"){let a={},l=s.cloudFront;typeof l.distributionId=="string"&&(a.distributionId=l.distributionId.trim()),Array.isArray(l.invalidationPaths)&&(a.invalidationPaths=l.invalidationPaths.map(c=>String(c??"").trim()).filter(c=>c.length>0)),Object.keys(a).length>0&&(o.cloudFront=a);}e[i]=o;}return e}function L(r){return r==="PROFESSIONAL"||r==="AGENCY"?r:void 0}function ie(r,e){if(!r||typeof r!="object")return null;let t=r,n=t.command;if(n!=="publish"&&n!=="crawl"&&n!=="deploy"&&n!=="invalidate"&&n!=="retry-timeouts"&&n!=="url"&&n!=="content-sync")return null;let i=Number.parseInt(String(t.intervalMinutes??"0"),10);if(!Number.isFinite(i)||i<1)return null;let s=String(t.id??`${n}-${e+1}`).trim();if(!s)return null;let o=String(t.deploymentProfile??"").trim(),u=String(t.url??"").trim(),a=Array.isArray(t.postTypes)?[...new Set(t.postTypes.map(c=>String(c??"").trim().toLowerCase().replace(/[^a-z0-9_-]/g,"")).filter(Boolean))]:[],l=Array.isArray(t.listingPaths)?[...new Set(t.listingPaths.map(c=>String(c??"").trim()).filter(Boolean))]:[];return n==="content-sync"&&a.length===0?null:{id:s,enabled:t.enabled!==false,command:n,intervalMinutes:i,...n==="publish"||n==="crawl"?{crawlMode:t.crawlMode==="incremental"?"incremental":"full"}:{},...(n==="publish"||n==="deploy"||n==="invalidate"||n==="content-sync")&&o?{deploymentProfile:o}:{},...u?{url:u}:{},...a.length>0?{postTypes:a}:{},...l.length>0?{listingPaths:l}:{},...typeof t.includePostTypeArchives=="boolean"?{includePostTypeArchives:t.includePostTypeArchives}:{},...typeof t.includeTaxonomyArchives=="boolean"?{includeTaxonomyArchives:t.includeTaxonomyArchives}:{},...typeof t.includeAuthorArchives=="boolean"?{includeAuthorArchives:t.includeAuthorArchives}:{},...typeof t.includeDateArchives=="boolean"?{includeDateArchives:t.includeDateArchives}:{},...typeof t.includePostsPage=="boolean"?{includePostsPage:t.includePostsPage}:{},...typeof t.includeSitemapChain=="boolean"?{includeSitemapChain:t.includeSitemapChain}:{}}}function U(r){let e=r&&typeof r=="object"?r:{},t=Array.isArray(e.rules)?e.rules.map((n,i)=>ie(n,i)).filter(n=>!!n):[];return {enabled:e.enabled===true,timezone:typeof e.timezone=="string"&&e.timezone.trim()!==""?e.timezone.trim():"UTC",rules:t}}function ne(r){if(!r||typeof r!="object")return;let e=r,t={};for(let i of ["accountId","siteId"]){let s=e[i];typeof s=="string"&&s.trim()!==""&&(t[i]=s.trim());}let n=Number(e.lastUpdate??0);return Number.isFinite(n)&&n>0&&(t.lastUpdate=Math.floor(n)),e.subscriber===true&&(t.subscriber=true),Object.keys(t).length>0?t:void 0}function x(r){let e=r&&typeof r=="object"?r:{},t=String(e.accountId??"").trim(),n=String(e.siteId??"").trim(),i=e.subscriber===true,s=ne(e.siteSettings),o={...s??{},...t?{accountId:s?.accountId??t}:{},...n?{siteId:s?.siteId??n}:{},...s?.subscriber===true||i?{subscriber:true}:{}},u={},a=String(e.apiBase??"").trim();a&&(u.apiBase=a);let l=String(e.runtimeToken??e.nonce??"").trim();l&&(u.runtimeToken=l);let c=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();c&&(u.virtualAssetBaseUrl=c),Object.keys(o).length>0&&(u.siteSettings=o);let d=L(e.subscriptionType);return d&&(u.subscriptionType=d),u}function se(r){try{let e=new URL(r);globalThis.location=e;}catch{}}function _(r){return typeof r=="string"?r:r instanceof URL?r.toString():r.url}function oe(r,e){let t=new Headers(r instanceof Request?r.headers:void 0);if(e?.headers)for(let[n,i]of new Headers(e.headers).entries())t.set(n,i);return t}async function $(r,e,t=5){let n=new URL(_(r)),i=String(e?.method??(r instanceof Request?r.method:"GET")).toUpperCase(),s=n.protocol==="http:"?X:ee,o=oe(r,e);return await new Promise((u,a)=>{let l=s.request(n,{method:i,headers:Object.fromEntries(o.entries()),...n.protocol==="https:"?{rejectUnauthorized:false}:{}},c=>{let d=[];c.on("data",g=>{d.push(Buffer.isBuffer(g)?g:Buffer.from(g));}),c.on("error",a),c.on("end",()=>{let g=c.statusCode??0,p=c.headers.location;if(t>0&&p&&[301,302,303,307,308].includes(g)){u($(new URL(p,n),{method:g===303?"GET":i},t-1));return}let m=new Headers;for(let[w,f]of Object.entries(c.headers))Array.isArray(f)?m.set(w,f.join(", ")):typeof f=="string"&&m.set(w,f);u(new Response(Buffer.concat(d),{status:g,statusText:c.statusMessage??"",headers:m}));});});l.on("error",a),l.end();})}function ae(r){let e=x(r.wpsuite),t={...e.siteSettings??{},...e.siteSettings?.subscriber===true||e.subscriptionType==="PROFESSIONAL"||e.subscriptionType==="AGENCY"?{subscriber:true}:{}},n=String(t.accountId??"").trim(),i=String(t.siteId??"").trim(),s=String(e.virtualAssetBaseUrl??e.uploadUrl??"").trim();if(r.wpsuite={...e.apiBase?{apiBase:e.apiBase}:{},...e.runtimeToken?{runtimeToken:e.runtimeToken}:{},...s?{virtualAssetBaseUrl:s}:{},...Object.keys(t).length>0?{siteSettings:t}:{},...e.subscriptionType?{subscriptionType:e.subscriptionType}:{}},!n||!i||!s)return false;se(r.sourceOrigin);let o=globalThis,a={...o.WpSuite??{},siteSettings:t,uploadUrl:s};return e.apiBase&&(a.apiBase=e.apiBase),o.WpSuite=a,true}async function le(r){let e=String(r.wpsuite?.virtualAssetBaseUrl??r.wpsuite?.uploadUrl??"").trim();if(!ae(r)){let i=r.wpsuite?.siteSettings,s=[String(i?.accountId??"").trim()?"":"accountId",String(i?.siteId??"").trim()?"":"siteId",e?"":"virtualAssetBaseUrl"].filter(Boolean);return {remote:null,diagnostic:{status:"invalid-runtime",virtualAssetBaseUrl:e,subscriptionType:null,error:`Missing WP Suite runtime field(s): ${s.join(", ")}.`,requests:[]}}}let t=globalThis.fetch,n=[];try{typeof t=="function"&&/^https?:\/\//i.test(e)&&(globalThis.fetch=(async(a,l)=>{let c=_(a);if(c.startsWith(e)){let d=(()=>{try{return new URL(c).pathname}catch{return c}})();try{let g=r.ignoreHttpsErrors&&c.startsWith("https://")?await $(a,l):await t(a,l);return n.push({path:d,status:g.status,ok:g.ok,error:null}),g}catch(g){throw n.push({path:d,status:null,ok:!1,error:g instanceof Error?g.message:String(g)}),g}}return t(a,l)}));let{getConfig:i}=await import('@smart-cloud/wpsuite-core'),s=await i("publisher"),o=s&&typeof s=="object"?s:null,u=L(o?.subscriptionType);return {remote:o,diagnostic:{status:o?"loaded":"unavailable",virtualAssetBaseUrl:e,subscriptionType:u??null,error:o?null:"WP Suite publisher config loader returned no configuration.",requests:n}}}catch(i){return {remote:null,diagnostic:{status:"unavailable",virtualAssetBaseUrl:e,subscriptionType:null,error:i instanceof Error?i.message:String(i),requests:n}}}finally{typeof t=="function"&&(globalThis.fetch=t);}}function ue(r,e){let t=re(e?.deploymentProfiles),n=String(e?.defaultDeploymentProfile??"").trim(),i=t[n]?n:"",s=L(e?.subscriptionType),o=x(r.wpsuite);return {...r,scheduler:U(e?.scheduler),deploymentProfiles:t,defaultDeploymentProfile:i,...s?{subscriptionType:s}:{},wpsuite:{...o,...o.siteSettings||s?{siteSettings:{...o.siteSettings??{},...o.siteSettings?.subscriber===true||s==="PROFESSIONAL"||s==="AGENCY"?{subscriber:true}:{}}}:{},...s?{subscriptionType:s}:{}}}}function E(r,e){let n=String(r||"").replace(/\\/g,"/").trim().replace(/^\/+|\/+$/g,"");if(!n)return e;let i=n.split("/").map(s=>s.trim()).filter(s=>s.length>0&&s!=="."&&s!=="..");return i.length>0?i.join("/"):e}function ce(){let r=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return r.trim()?h.resolve(r):""}function N(r,e,t){let n=String(e||"").trim();return n&&h.isAbsolute(n)?h.resolve(n):h.resolve(r,E(n,t))}async function C(r,e={}){let t=String("").trim()||process.env.PUBLISHER_CONFIG||"publisher.config.json",n=await b.readFile(t,"utf8"),i=JSON.parse(n);i.sourceOrigin=i.sourceOrigin.replace(/\/$/,""),i.targetOrigin=j(i.targetOrigin),i.ignoreHttpsErrors??=false,i.outputDir=String(i.outputDir||"export").trim()||"export",i.urlRewriteMode||=i.targetOrigin==="."?"relative":"absolute",i.noJavaScriptRenderPathPrefixes||=[],i.seedPaths||=[],i.generated404RequestPath=te(i.generated404RequestPath),i.sitemapPaths||=["/sitemap_index.xml","/sitemap.xml"],i.allowedAssetHosts||=[],i.assetPathPrefixes||=["/wp-content/","/wp-includes/","/static/","/assets/","/build/","/_next/","/docs/","/sitemap","/robots.txt","/llms.txt"],i.blockedPathPrefixes||=[],i.blockedSearchFragments||=[],i.concurrency||=1,i.maxPages||=0,i.extraReplacements=k(i.extraReplacements),i.postCrawlCopyMap=k(i.postCrawlCopyMap),i.logDir=String(i.logDir||"logs").trim()||"logs",i.verbose??=false,i.logLevel||=i.verbose?"debug":"info",i.s3SyncMode||="sdk-upload-delete",i.readiness||={waitForSelector:null,waitForFunction:null,timeoutMs:1500,fallbackWaitMs:1500},i.readiness.timeoutMs??=1500,i.readiness.fallbackWaitMs??=1500,i.viewport||={width:1440,height:1200},i.navigationTimeoutMs||=3e4,i.assetDownloadConcurrency=Number(i.assetDownloadConcurrency)>0?Number(i.assetDownloadConcurrency):i.concurrency,i.rewriteConcurrency=Number(i.rewriteConcurrency)>0?Number(i.rewriteConcurrency):i.assetDownloadConcurrency,i.wpsuite=x(i.wpsuite),i.scheduler=U(void 0),i.deploymentProfiles={},i.defaultDeploymentProfile="",i.deploymentTargetOverride=String(i.deploymentTargetOverride??"").trim();let s=await le(i);e.onRemotePublisherConfigDiagnostic?.(s.diagnostic);let o=ue(i,s.remote),u=ce(),a=u?h.resolve(u,".."):"";return a?(o.outputDir=N(a,o.outputDir,"export"),o.logDir=N(a,o.logDir,"logs")):(h.isAbsolute(o.outputDir)||(o.outputDir=E(o.outputDir,"export")),h.isAbsolute(o.logDir)||(o.logDir=E(o.logDir,"logs"))),o}function ge(r){let e=r/6e4;if(Number.isInteger(e)&&e>=1)return `${e} minute${"s"}`;let t=Math.ceil(r/1e3);return `${t} second${t===1?"":"s"}`}async function M(r,e,t){let n=new AbortController,i=globalThis.setTimeout(()=>{n.abort(new Error(`${r} timed out after ${ge(e)}.`));},e);try{return await t({abortController:n,httpOptions:{abortSignal:n.signal,requestTimeout:e}})}finally{globalThis.clearTimeout(i);}}var de=".deploy-plan.json",me="deploy-plan.json";function he(){let r=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"";return r.trim()?h.resolve(r):""}function fe(r){let e=String(r||"").replace(/\\/g,"/").replace(/^\/+/,"").trim(),t=h.posix.normalize(e);return !e||!t||t==="."||/^[a-zA-Z]:/.test(t)||t.startsWith("../")||t===".."?null:t}function ye(r){let e=String(r||"").trim();if(!e.startsWith("/")||e.startsWith("//")||e.includes("*")||e.includes("#"))return null;try{let t=new URL(e,"https://content-sync.invalid");return t.origin!=="https://content-sync.invalid"?null:`${h.posix.normalize(t.pathname)}${t.search}`}catch{return null}}function P(r){return [...new Set(r.map(fe).filter(e=>e!==null))]}function Pe(r,e){let t={generatedAt:String(e.generatedAt||new Date().toISOString()),outputDir:h.resolve(r.outputDir),runMode:e.runMode,crawlMode:e.crawlMode,fullSyncRequired:!!e.fullSyncRequired,changedFiles:P(e.changedFiles||[]),deletedFiles:P(e.deletedFiles||[]),rewriteTargets:P(e.rewriteTargets||[])};return e.schemaVersion===2?{...t,schemaVersion:2,runMode:"content-sync",crawlMode:"incremental",fullSyncRequired:false,consumerId:String(e.consumerId||"").trim(),fromSequence:Math.max(0,Number(e.fromSequence)||0),toSequence:Math.max(0,Number(e.toSequence)||0),impactHash:String(e.impactHash||"").trim(),uploadGroups:{assets:P(e.uploadGroups?.assets||[]),content:P(e.uploadGroups?.content||[]),listings:P(e.uploadGroups?.listings||[]),sitemapLeaves:P(e.uploadGroups?.sitemapLeaves||[]),sitemapIndexes:P(e.uploadGroups?.sitemapIndexes||[])},invalidationPaths:[...new Set((e.invalidationPaths||[]).map(ye).filter(n=>n!==null))].sort()}:{schemaVersion:1,...t,runMode:e.runMode}}function be(r){if(!r||typeof r!="object")return false;let e=r;if(e.schemaVersion===2){let t=e;return t.runMode==="content-sync"&&t.crawlMode==="incremental"&&t.fullSyncRequired===false&&typeof t.generatedAt=="string"&&typeof t.outputDir=="string"&&typeof t.consumerId=="string"&&t.consumerId.trim()!==""&&Number.isSafeInteger(t.fromSequence)&&Number.isSafeInteger(t.toSequence)&&Number(t.toSequence)>=Number(t.fromSequence)&&typeof t.impactHash=="string"&&/^[a-f0-9]{64}$/.test(t.impactHash)&&Array.isArray(t.changedFiles)&&Array.isArray(t.deletedFiles)&&Array.isArray(t.rewriteTargets)&&!!t.uploadGroups&&Array.isArray(t.uploadGroups.assets)&&Array.isArray(t.uploadGroups.content)&&Array.isArray(t.uploadGroups.listings)&&Array.isArray(t.uploadGroups.sitemapLeaves)&&Array.isArray(t.uploadGroups.sitemapIndexes)&&Array.isArray(t.invalidationPaths)}return e.schemaVersion===1&&typeof e.generatedAt=="string"&&typeof e.outputDir=="string"&&(e.runMode==="full"||e.runMode==="retry-timeouts"||e.runMode==="single-url")&&(e.crawlMode==="full"||e.crawlMode==="incremental")&&typeof e.fullSyncRequired=="boolean"&&Array.isArray(e.changedFiles)&&Array.isArray(e.deletedFiles)&&Array.isArray(e.rewriteTargets)}function we(r){let e=h.join(h.resolve(r.outputDir),de),t=he();return t?[h.join(t,me),e]:[e]}async function q(r){let e=h.resolve(r.outputDir);for(let t of we(r))try{let n=await b.readFile(t,"utf8"),i=JSON.parse(n);if(!be(i)||h.resolve(i.outputDir)!==e)continue;return Pe(r,i)}catch{}return null}function Se(r){return typeof r.subscriptionType=="string"&&r.subscriptionType.trim()!==""}function W(r){let e="";for(let n=0;n<r.length;n++){let i=r[n];if(i==="--profile"){let s=(r[n+1]||"").trim();if(!s)throw new Error("Missing value for --profile.");e=s,n+=1;}else if(i.startsWith("--profile=")){let s=i.slice(10).trim();if(!s)throw new Error("Missing value for --profile.");e=s;}}let t=String(process.env.PUBLISHER_DEPLOY_PROFILE||process.env.PUBLISHER_DEPLOYMENT_PROFILE||"").trim();return e||t||null}function ve(r,e){return {...r,...e??{}}}function Ie(r,e){return {...r,...e??{},invalidationPaths:[...(e?.invalidationPaths??r.invalidationPaths)||[]]}}function B(r,e){let t=String(e??r.deploymentTargetOverride??"").trim();if(!Se(r)){if(t)throw new Error(`Deployment target "${t}" requires an active WPSuite subscription and remote publisher config.`);return {name:null,profile:null,config:r}}let n=String(t||r.defaultDeploymentProfile||"").trim();if(!n)return {name:null,profile:null,config:r};let i=r.deploymentProfiles?.[n];if(!i)throw new Error(`Unknown deployment profile "${n}". Check the linked WPSuite publisher configuration.`);return {name:n,profile:i,config:{...r,targetOrigin:i.targetOrigin??r.targetOrigin,s3:ve(r.s3,i.s3),cloudFront:Ie(r.cloudFront,i.cloudFront)}}}var H={error:0,warn:1,info:2,debug:3},Ce=/^(?:authorization|proxyAuthorization|runtimeToken|siteKey|nonce|accessToken|refreshToken|accessKeyId|secretAccessKey|sessionToken|xStaticPublisherToken|xApiKey)$/i;function I(r){return r.replace(/((?:x-static-publisher-token|authorization|proxy-authorization|x-api-key|aws-access-key-id|aws-secret-access-key|aws-session-token)\s*:\s*)[^\r\n]+/gi,"$1[REDACTED]").replace(/\b(Basic|Bearer)\s+[^\s]+/gi,"$1 [REDACTED]").replace(/([?&](?:token|access_token|refresh_token|api_key|key|nonce)=)[^&\s]+/gi,"$1[REDACTED]").replace(/((?:"|')?(?:runtimeToken|siteKey|nonce|accessToken|refreshToken|accessKeyId|secretAccessKey|sessionToken)(?:"|')?\s*[:=]\s*(?:"|'))[^"']+/gi,"$1[REDACTED]")}function T(r){return typeof r=="string"?I(r):Array.isArray(r)?r.map(e=>T(e)):r instanceof Error?{name:r.name,message:I(r.message),...r.stack?{stack:I(r.stack)}:{}}:r&&typeof r=="object"?Object.fromEntries(Object.entries(r).map(([e,t])=>[e,Ce.test(e)?"[REDACTED]":T(t)])):r}function V(r){return r?T(r):void 0}var z=process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"",D=z?h.join(z,"current-progress.json"):"",J=Promise.resolve();function G(r){return r.includes("crawl")?"crawl":r.includes("deploy")?"deploy":r.includes("invalidate")?"invalidate":r}function De(r,e){let t={...r},n=new Set(["pagesQueued","pagesRendered","assetsQueued","sitemapsQueued","pagesDiscovered","assetsDiscovered","sitemapsDiscovered","pagesSaved","assetsSaved","donePages","doneAssets","doneSitemaps","changedTextFiles","uploaded","failed","index","totalFiles","pageQueue","assetQueue","sitemapQueue"]);for(let[i,s]of Object.entries(e)){let o=t[i];if(typeof o=="number"&&typeof s=="number"&&n.has(i)){t[i]=Math.max(o,s);continue}t[i]=s;}return t}function Te(r,e,t){D&&(J=J.then(async()=>{let n=new Date,i=n.toISOString();await b.mkdir(h.dirname(D),{recursive:true});let s=await b.readFile(D,"utf8").then(A=>JSON.parse(A)).catch(()=>null),o=s&&typeof s.details=="object"&&s.details?s.details:{},u=G(r),a=s?.currentStep||G(s?.source||""),l=s?.startedAt||i,c={...s?.stepDurationsSec??{}},d=s?.stepStartedAt||i;if(a&&a!==u&&s?.stepStartedAt){let A=Math.max(0,Math.round((n.getTime()-new Date(s.stepStartedAt).getTime())/1e3));c[a]=(c[a]??0)+A,d=i;}let g=Math.max(0,Math.round((n.getTime()-new Date(d).getTime())/1e3)),p=Math.max(0,Math.round((n.getTime()-new Date(l).getTime())/1e3)),m=I(e),w=V(t)??{},f={checkedAt:i,source:r,message:m,details:De(o,w),startedAt:l,currentStep:u,stepStartedAt:d,stepElapsedSec:g,totalElapsedSec:p,stepDurationsSec:c};await b.writeFile(D,JSON.stringify(f,null,2),"utf8");}).catch(()=>{}));}async function Re(r,e){await b.mkdir(h.dirname(r),{recursive:true}),await b.appendFile(r,`${JSON.stringify(T(e))}
|
|
2
|
+
`,"utf8");}var v=class{constructor(e,t,n="info"){this.logDir=e;this.logFile=t;this.level=n;this.ensureLogFileReady();}logDir;logFile;level;startedAt=Date.now();marks=new Map;initPromise=null;writeQueue=Promise.resolve();writeError=null;get logPath(){return h.join(this.logDir,this.logFile)}artifactPath(e){return this.logFile.endsWith(".log.jsonl")?h.join(this.logDir,this.logFile.replace(/\.log\.jsonl$/u,`${e}.jsonl`)):h.join(this.logDir,`${this.logFile}${e}.jsonl`)}get errorsPath(){return this.artifactPath(".errors")}get rejectedPath(){return this.artifactPath(".rejected")}ensureLogFileReady(){return this.initPromise||(this.initPromise=(async()=>{await b.mkdir(this.logDir,{recursive:true}),await b.writeFile(this.logPath,"","utf8");})()),this.initPromise}enqueueTask(e){this.writeQueue=this.writeQueue.then(e).catch(t=>{this.writeError=t instanceof Error?t:new Error(String(t));});}enqueueLine(e){this.enqueueTask(async()=>{await this.ensureLogFileReady(),await b.appendFile(this.logPath,`${e}
|
|
3
|
+
`,"utf8");});}enqueueJsonLine(e,t){this.enqueueTask(()=>Re(e,t));}accepts(e){return H[e]<=H[this.level]}push(e,t,n){if(!this.accepts(e))return;let i=I(t),s=V(n),o=JSON.stringify({time:new Date().toISOString(),level:e,message:i,...s||{}});this.enqueueLine(o),e==="error"?console.error(`[ERROR] ${i}`,s?JSON.stringify(s):""):e==="warn"?console.warn(`[WARN] ${i}`,s?JSON.stringify(s):""):console.log(`[${e.toUpperCase().padEnd(5)}] ${i}`);}info(e,t){this.push("info",e,t);}progress(e,t){Te(this.logFile,e,t);}debug(e,t){this.push("debug",e,t);}warn(e,t){this.push("warn",e,t);}reject(e,t,n,i,s){let o={kind:e,url:t,reason:n,...i?{source:i}:{},...s||{}};this.enqueueJsonLine(this.rejectedPath,o),this.accepts("debug")&&this.push("debug",`Rejected ${e} ${t}: ${n}`,o);}error(e,t){this.enqueueJsonLine(this.errorsPath,{message:e,...t||{}}),this.push("error",e,t);}mark(e){this.marks.set(e,Date.now());}endMark(e,t){let n=this.marks.get(e);if(!n)return;let i=Date.now()-n,s=Number((i/1e3).toFixed(2));this.push("info",`Timing ${e}: ${s}s`,{name:e,ms:i,seconds:s,...t||{}});}async flush(){let e=Date.now()-this.startedAt,t=Number((e/1e3).toFixed(2));if(this.push("info",`Total time: ${t}s`,{name:"total",ms:e,seconds:t}),await this.writeQueue,this.writeError)throw this.writeError}};function Ee(){let r=String(process.env.STATIC_PUBLISHER_RUNTIME_DIR||process.env.WPSUITE_STATIC_PUBLISHER_RUNTIME_DIR||"").trim();return r?h.join(h.resolve(r),"content-sync-invalidation.json"):""}async function F(r,e){if(!r)return;await b.mkdir(h.dirname(r),{recursive:true});let t=`${r}.${process.pid}.${Date.now()}.tmp`;await b.writeFile(t,JSON.stringify({...e,updatedAt:new Date().toISOString()},null,2),"utf8"),await b.rename(t,r);}async function Le(r,e,t){if(!r)return null;try{let n=JSON.parse(await b.readFile(r,"utf8"));if(n.schemaVersion!==1||n.distributionId!==e||n.impactHash!==t||!Array.isArray(n.batches))throw new Error("Content-sync invalidation state does not match the deploy plan.");return n}catch(n){if(n.code==="ENOENT")return null;throw n}}function xe(r,e=3e3){let t=[];for(let n=0;n<r.length;n+=e)t.push(r.slice(n,n+e));return t}async function Y(r=process.argv.slice(2)){let e=await C(),t=W(r),n=B(e,t),i=n.config,s=new v(i.logDir||"logs","invalidate.log.jsonl",i.logLevel??"info"),o=r.includes("--content-sync"),u=await q(e);if(o&&u?.schemaVersion!==2)throw new Error("Content-sync invalidation requires a valid schema-2 targeted deploy plan.");if(n.name&&s.info(`Using deployment profile: ${n.name}`),!i.cloudFront.distributionId){s.info("No CloudFront distributionId configured; skipping invalidation."),await s.flush();return}let a=u?.schemaVersion===2?u.invalidationPaths:i.cloudFront.invalidationPaths.length>0?i.cloudFront.invalidationPaths:["/*"];if(u?.schemaVersion===2&&a.some(p=>p==="/*"))throw new Error("Content-sync cannot use a whole-distribution invalidation.");if(a.length===0){s.info("The targeted deploy plan has no CloudFront paths to invalidate."),await s.flush();return}let l=i.cloudFront.distributionId,c=new CloudFrontClient({region:"us-east-1",maxAttempts:5});if(s.mark("invalidate"),u?.schemaVersion!==2){let p=`smartcloud-static-publisher-${Date.now()}`;await M(`CloudFront invalidation for distribution ${l}`,3e5,({httpOptions:m})=>c.send(new CreateInvalidationCommand({DistributionId:l,InvalidationBatch:{CallerReference:p,Paths:{Quantity:a.length,Items:a}}}),m)),s.endMark("invalidate"),await s.flush();return}let d=Ee(),g=await Le(d,l,u.impactHash);g||(g={schemaVersion:1,distributionId:l,impactHash:u.impactHash,updatedAt:new Date().toISOString(),batches:xe(a).map((p,m)=>({index:m,callerReference:`wpsuite-content-sync-${u.impactHash.slice(0,32)}-${m}`,paths:p,invalidationId:null,status:"pending"}))},await F(d,g));for(let p of g.batches){if(!p.invalidationId){let m=await M(`CloudFront targeted invalidation batch ${p.index+1}`,3e5,({httpOptions:f})=>c.send(new CreateInvalidationCommand({DistributionId:l,InvalidationBatch:{CallerReference:p.callerReference,Paths:{Quantity:p.paths.length,Items:p.paths}}}),f)),w=String(m.Invalidation?.Id||"").trim();if(!w)throw new Error("CloudFront did not return an invalidation ID.");p.invalidationId=w,p.status="created",await F(d,g);}await waitUntilInvalidationCompleted({client:c,maxWaitTime:900,minDelay:2,maxDelay:15},{DistributionId:l,Id:p.invalidationId}),p.status="completed",await F(d,g),s.info(`CloudFront invalidation batch ${p.index+1}/${g.batches.length} completed.`,{invalidationId:p.invalidationId,pathCount:p.paths.length});}s.endMark("invalidate"),await s.flush();}Y().catch(async r=>{console.error(r);try{let e=await C().catch(()=>null),t=new v(e?.logDir??"logs","invalidate.log.jsonl","debug");t.error(`Unhandled error: ${r instanceof Error?r.message:String(r)}`,r instanceof Error?{stack:r.stack}:void 0),await t.flush();}catch{}process.exit(1);});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smart-cloud/publisher-exporter",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.40",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Headless Playwright static publisher for WordPress/Elementor sites with sitemap-only page discovery, strict asset capture, escaped URL rewrite, structured logs, and targeted retry modes.",
|