@smart-cloud/publisher-exporter 1.1.70 → 1.1.71
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/README.md +11 -0
- package/dist/remote-worker.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
It is designed to run outside WordPress. The WordPress plugin only manages runtime config, queue state, and logs.
|
|
6
6
|
|
|
7
|
+
## Release notes
|
|
8
|
+
|
|
9
|
+
### 1.1.71
|
|
10
|
+
|
|
11
|
+
- Restore `--no-zygote` for Lambda Chromium launches while keeping `--single-process` disabled. Browser and renderer processes remain separate.
|
|
12
|
+
- Retain one reusable browser per render batch and a fresh, non-persistent browser context for each page. Cookies and browser storage do not carry over between pages; the browser closes and its owned temporary files are cleaned at the batch boundary.
|
|
13
|
+
- Test the actual Playwright Headless Shell instead of substituting full Chromium. The lifecycle check runs three batches of 20 pages, verifies context isolation, samples browser-tree memory and temporary storage, and invokes the production temporary-file cleanup between batches.
|
|
14
|
+
- Validate the corrected launch configuration in an isolated ARM64 Lambda: 62 rendered pages across 11 invocations in the same warm execution environment. Local smoke tests remain additional checks, not a substitute for Lambda validation.
|
|
15
|
+
|
|
16
|
+
Upgrade the Lambda image's pinned exporter version to `1.1.71` and redeploy the worker stack. Updating only the WordPress coordinator's npm package does not update existing Lambda images. No architecture change is required.
|
|
17
|
+
|
|
7
18
|
## Install
|
|
8
19
|
|
|
9
20
|
Global install:
|
package/dist/remote-worker.js
CHANGED
|
@@ -2,6 +2,6 @@ import {S3Client,HeadObjectCommand,CopyObjectCommand,DeleteObjectsCommand,PutObj
|
|
|
2
2
|
`)?`\r
|
|
3
3
|
`:`
|
|
4
4
|
`;return e.replace(/<head\b[^>]*>/i,o=>`${o}${n} ${t}`)}function vt(e){let t=ve(e).trim();return t.startsWith("{")||t.startsWith("[")||t.includes("\\/")||/"@context"|"@type"/.test(t)}function Wt(e,t){let r=[...new Set(t)].filter(s=>s.includes("/")&&!/\\+\//.test(s)).map(s=>[s,X(s)]).filter(([s,a])=>s!==a).sort((s,a)=>a[0].length-s[0].length);if(!r.length)return e;let n=s=>{let a=s;for(let[i,c]of r)a=a.split(i).join(c);return a},o=e.replace(/(<script\b[^>]*\btype=["']application\/(?:ld\+)?json["'][^>]*>)([\s\S]*?)(<\/script>)/gi,(s,a,i,c)=>`${a}${n(i)}${c}`);return o=o.replace(/(<meta\b[^>]*\bcontent=(['"]))([\s\S]*?)(\2[^>]*>)/gi,(s,a,i,c,u)=>vt(c)?`${a}${n(c)}${u}`:s),o}function Ct(e,t){if(!t)return null;let r=E.dirname(E.resolve(t)),n=E.resolve(e.outputDir),o=E.relative(r,n).replace(/\\/g,"/");return o?(o.startsWith(".")||(o=`./${o}`),o.endsWith("/")?o:`${o}/`):"./"}function Ot(e,t,r){let n=Ct(t,r);if(!n)return e;let o=e;for(let s of bt){let a=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=new RegExp(`(?:\\.{1,}/)+${a}`,"g"),c=new RegExp(`(?<!\\.)/${a}`,"g");o=o.replace(i,`${n}${s}`).replace(c,`${n}${s}`);let u=s.replace(/\//g,"\\/"),l=n.replace(/\//g,"\\/"),d=u.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),m=new RegExp(`(?:\\.{1,}\\\\/)+${d}`,"g"),p=new RegExp(`(?:\\.{1,}(?:\\\\/|\\\\))+${d}`,"g"),y=new RegExp(`(?<![\\.\\\\])\\/${d}`,"g");o=o.replace(m,`${l}${u}`).replace(p,`${l}${u}`).replace(y,`${l}${u}`);}return o}function pe(e,t,r){if(e.urlRewriteMode==="absolute")return t;let n=(()=>{try{return new URL(t,e.targetOrigin==="."?"https://relative.invalid":e.targetOrigin)}catch{return null}})(),o=n?n.pathname:We(t,e.targetOrigin),s=n?`${n.search}${n.hash}`:"";return e.urlRewriteMode==="root-relative"?`${o}${s}`:`${Ce(e.outputDir,r,o)}${s}`}function de(e,t,r,n,o){Z(e,r,pe(t,n,o));}function $t(e,t,r,n,o){if(!r||r===n)return;Z(e,r,n);let s=pe(t,r,o),a=pe(t,n,o);Z(e,s,a);}function $e(e,t,r,n,o={}){let s=e,a={};de(a,t,t.sourceOrigin,t.targetOrigin,n);for(let[c,u]of Object.entries(t.extraReplacements))de(a,t,c,u,n);for(let[c,u]of Object.entries(r))de(a,t,c,u,n);for(let[c,u]of Object.entries(o)){let l=r[c];!l||l===u||$t(a,t,u,l,n);}let i=Object.entries(a).sort((c,u)=>u[0].length-c[0].length);for(let[c,u]of i)s=xt(s,c,u);return t.urlRewriteMode!=="absolute"&&(s=Ot(s,t,n)),s=Wt(s,i.map(([,c])=>c)),It(t,s,n)&&(s=Tt(s)),s}var me=String(process.env.PUBLISHER_PROGRESS_TABLE??"").trim(),Me=Number(process.env.PUBLISHER_PROGRESS_RETENTION_SECONDS??604800),jt=Number.isFinite(Me)?Math.max(86400,Me):604800,Ae=me?new DynamoDBClient({}):null;function Vt(e){return e.operation==="render"||e.operation==="asset"?e.urls.length:e.operation==="rewrite"?e.items.length:e.items.length+(e.deleteRelativeKeys?.length??0)}async function Ut(e){if(!(!Ae||!me))try{let t=Math.floor(Date.now()/1e3)+jt;await Ae.send(new UpdateItemCommand({TableName:me,Key:{jobId:{S:e.jobId},taskId:{S:e.taskId}},UpdateExpression:"SET #operation = :operation, #status = :status, completedItems = :completedItems, failedItems = :failedItems, totalItems = :totalItems, #sequence = :sequence, updatedAt = :updatedAt, expiresAt = :expiresAt"+(e.requestId?", requestId = :requestId":""),ConditionExpression:"attribute_not_exists(#sequence) OR #sequence < :sequence",ExpressionAttributeNames:{"#operation":"operation","#status":"status","#sequence":"sequence"},ExpressionAttributeValues:{":operation":{S:e.operation},":status":{S:e.status},":completedItems":{N:String(e.completedItems)},":failedItems":{N:String(e.failedItems)},":totalItems":{N:String(e.totalItems)},":sequence":{N:String(e.sequence)},":updatedAt":{S:e.updatedAt},":expiresAt":{N:String(t)},...e.requestId?{":requestId":{S:e.requestId}}:{}}}));}catch(t){if(t.name==="ConditionalCheckFailedException")return;console.warn(JSON.stringify({message:"Remote worker progress status could not be written.",jobId:e.jobId,taskId:e.taskId,error:t instanceof Error?t.message:String(t)}));}}var Y=class{#t;#o;#e;#s;#i;#a=-1;#c=0;#n=0;#l=0;constructor(t,r,n=Ut){this.#t=t,this.#o=r??null,this.#e=Vt(t),this.#s=Math.max(1,Math.ceil(this.#e/20)),this.#i=n;}async started(){await this.#r("running",0,0,0);}async updated(t,r){this.#n=t,this.#l=r;let n=t+r,o=Date.now();n<this.#e&&n-this.#a<this.#s&&o-this.#c<5e3||await this.#r("running",t,r,n+1);}async completed(t){await this.#r(t.status,t.completedItems,t.failedItems,this.#e+2);}async failed(){let t=Math.min(this.#e-this.#n,Math.max(1,this.#l));await this.#r("failed",this.#n,t,this.#e+3);}async#r(t,r,n,o){this.#a=r+n,this.#c=Date.now(),await this.#i({jobId:this.#t.jobId,taskId:this.#t.taskId,operation:this.#t.operation,status:t,completedItems:r,failedItems:n,totalItems:this.#e,sequence:o,updatedAt:new Date().toISOString(),requestId:this.#o});}};var Lt=/^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+(?:\s*;.*)?$/u;function _t(e){try{return new URL(e).pathname}catch{return e}}function Q(e,t,r){let n=String(e??"").trim();if(Lt.test(n))return n;let o=je.lookup(_t(t));return o?je.contentType(o)||o:r}function ge(e){return String(e??"").split(";").map(t=>t.trim().toLowerCase()).filter(Boolean).join(";")}var Le="playwright_chromiumdev_profile-",Ft="/tmp/wpsuite-publisher-browser";function x(e){return Math.round(e/1024/1024*100)/100}async function Ve(e){try{let t=await statfs(e),r=t.blocks*t.bsize,n=t.bavail*t.bsize;return {path:e,totalMiB:x(r),availableMiB:x(n),usedMiB:x(r-n)}}catch(t){return {path:e,totalMiB:null,availableMiB:null,usedMiB:null,error:t instanceof Error?t.message:String(t)}}}async function Ht(e){return (await fe(e)).filter(t=>t.startsWith(Le))}async function fe(e){try{return (await readdir(e,{withFileTypes:!0})).map(t=>t.name).sort()}catch(t){if(t.code==="ENOENT")return [];throw t}}function he(){return E.resolve(process.env.PUBLISHER_BROWSER_TEMP_ROOT?.trim()||Ft)}async function _e(e=he()){let t=Be(e),r=E.join(t,"home"),n=E.join(t,"cache"),o=E.join(t,"config");await Promise.all([t,r,n,o].map(s=>mkdir(s,{recursive:true}))),process.env.TMPDIR=t,process.env.HOME=r,process.env.XDG_CACHE_HOME=n,process.env.XDG_CONFIG_HOME=o;}async function Ke(e=he()){let t=process.memoryUsage(),[r,n,o,s]=await Promise.all([Ve(e),Ve("/dev/shm"),Ht(e),fe(e)]);return {processMemoryMiB:{rss:x(t.rss),heapUsed:x(t.heapUsed),heapTotal:x(t.heapTotal),external:x(t.external),arrayBuffers:x(t.arrayBuffers)},tempStorage:r,sharedMemory:n,playwrightProfiles:{count:o.length,names:o.slice(0,20)},tempEntries:{count:s.length,names:s.slice(0,20)}}}function Be(e){let t=E.resolve(e);if(t===E.parse(t).root)throw new Error(`Refusing to clean filesystem root: ${t}`);if(t==="/tmp"||t==="/var/tmp")throw new Error(`Refusing to clean shared temp root: ${t}`);return t}async function Ne(e=he()){let t=Be(e),r=await fe(t);for(let n of r)await rm(E.join(t,n),{recursive:true,force:true,maxRetries:3,retryDelay:50});return r}function zt(e){let t=e.split("\0",1)[0]??"",r=E.basename(t).toLowerCase();return r.includes("chrome-headless-shell")||r==="chrome_crashpad_handler"||r==="chromium"||r==="chromium-browser"||e.includes(Le)&&/(?:chrome|chromium)/i.test(e)}async function De(e="/proc",t=r=>process.kill(r,"SIGKILL")){let r;try{r=await readdir(e,{withFileTypes:!0});}catch(o){if(o.code==="ENOENT")return [];throw o}let n=[];for(let o of r){if(!o.isDirectory()||!/^\d+$/.test(o.name))continue;let s=Number(o.name);if(!Number.isSafeInteger(s)||s<1||s===process.pid)continue;let a;try{a=await readFile(E.join(e,o.name,"cmdline"),"utf8");}catch(i){if(["ENOENT","EACCES","EPERM","ESRCH"].includes(String(i.code)))continue;throw i}if(zt(a))try{t(s),n.push(s);}catch(i){if(["ESRCH","EPERM"].includes(String(i.code)))continue;throw i}}return n.length>0&&await setTimeout(100),n.sort((o,s)=>o-s)}var B={},qe=false;function Jt(e){if(e)try{let t=new URL(e);return t.username="",t.password="",t.search="",t.hash="",t.toString()}catch{return}}function Fe(e){return {...e,...e.url?{url:Jt(e.url)}:{}}}function He(e){return e instanceof Error?{errorName:e.name,errorMessage:e.message,...e.stack?{errorStack:e.stack}:{}}:{error:String(e)}}function we(e,t={}){try{writeSync(2,`${JSON.stringify({level:"ERROR",message:"Remote worker runtime diagnostic.",event:e,...B,...t,timestamp:new Date().toISOString()})}
|
|
5
|
-
`);}catch{}}function ze(){qe||(qe=true,process.on("uncaughtExceptionMonitor",(e,t)=>{we("runtime.uncaught-exception",{origin:t,...He(e)});}),process.on("exit",e=>{we("runtime.process-exit",{exitCode:e});}));}async function g(e,t,r={},n="info"){try{B=Fe(t);let o=null;try{o=await Ke();}catch(a){r={...r,resourceSnapshotError:a instanceof Error?a.message:String(a)};}let s=JSON.stringify({message:"Remote worker checkpoint.",event:e,...B,...r,...o?{resources:o}:{}});console[n](s);}catch(o){we("checkpoint.write-failed",{checkpointEvent:e,...He(o)});}}function ee(e){B=Fe(e);}function Ge(){B={};}var $=String(process.env.PUBLISHER_WORKSPACE_BUCKET??"").trim(),k=L(process.env.PUBLISHER_WORKSPACE_PREFIX??""),te=String(process.env.PUBLISHER_ALLOWED_OPERATION??"").trim(),M=String(process.env.PUBLISHER_EXPORTER_VERSION??"unknown").trim(),N=String(process.env.PUBLISHER_PROXY_URL??"").trim(),nr=or(process.env.PUBLISHER_ALLOWED_TARGETS??"[]"),Ye=new S3Client({}),Je=new Map,b=null,D=false;ze();function or(e){try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(r=>{if(!r||typeof r!="object")return !1;let n=r;return ["id","bucketName","prefix","region"].every(o=>typeof n[o]=="string")}).map(r=>({...r,prefix:L(r.prefix)})):[]}catch{return []}}function ye(){if(!$)throw new Error("PUBLISHER_WORKSPACE_BUCKET is required.")}async function Re(e,t){try{let r=await De();r.length>0&&await g(`browser.stale-processes-killed.${t}`,e,{killedProcesses:r.length,killedProcessIds:r},"warn");let n=await Ne();n.length>0&&await g(`browser.temp-entries-removed.${t}`,e,{removedEntries:n.length,removedEntryNames:n.slice(0,20)}),await _e();}catch(r){if(await g(`browser.profile-cleanup-failed.${t}`,e,{error:r instanceof Error?r.message:String(r)},"error"),t==="before-launch")throw r}}async function sr(e){if(b){let r=await b.catch(()=>null);if(r?.isConnected())return r}await g("browser.launch-preparing",e),await Re(e,"before-launch"),await g("browser.launch-started",e);let t=chromium.launch({headless:true,args:["--no-sandbox","--disable-setuid-sandbox","--disable-gpu"],...N?{proxy:{server:N}}:{}});b=t;try{let r=await t;return r.once("disconnected",()=>{b===t&&(b=null);let n=D;ee(e),g("browser.disconnected",e,{expected:n},n?"info":"error");}),await g("browser.launch-succeeded",e),r}catch(r){throw b===t&&(b=null),await g("browser.launch-failed",e,{error:r instanceof Error?r.message:String(r)},"error"),r}}async function Qe(e){let t=b;if(b=null,t){let r=await t.catch(()=>null);r&&(D=true,await r.close().catch(async n=>{await g("browser.close-failed",e,{error:n instanceof Error?n.message:String(n)},"warn");}),D=false);}await Re(e,"after-close");}async function ir(e,t){let r;for(let n=1;n<=2;n+=1){let o=await sr({...t,attempt:n}),s=null;try{s=await o.newContext({viewport:e.options.viewport,ignoreHTTPSErrors:e.options.ignoreHttpsErrors,javaScriptEnabled:e.options.javaScriptEnabled,serviceWorkers:"block",userAgent:"WPSuiteStaticPublisher/remote-worker-v1"}),e.options.javaScriptEnabled&&await ar(s);let a=await xe(s);return {context:s,page:await s.newPage(),networkPolicyViolation:a.getViolation}}catch(a){r=a,await s?.close().catch(()=>{}),b=null,D=true,await o.close().catch(()=>{}),D=false,await Re({...t,attempt:n},"after-close");}}throw r instanceof Error?r:new Error(`Unable to create a Chromium page: ${String(r)}`)}async function ar(e){await e.addInitScript(()=>{Object.defineProperty(window,"__WPSUITE_STATIC_EXPORT__",{value:true,writable:false,configurable:true});let t=r=>{if(r==null||String(r)==="")return true;try{let n=new URL(String(r),window.location.href),o=new URL(window.location.href);return n.hash="",o.hash="",n.href===o.href}catch{return false}};try{let r=window.location.assign.bind(window.location),n=window.location.replace.bind(window.location);Object.defineProperty(window.location,"assign",{configurable:!0,value:o=>{if(!t(o))return r(o)}}),Object.defineProperty(window.location,"replace",{configurable:!0,value:o=>{if(!t(o))return n(o)}}),Object.defineProperty(window.location,"reload",{configurable:!0,value:()=>{}});}catch{}});}async function cr(e,t){await e.evaluate(async r=>{await new Promise(n=>{let o=0,s=700,a=Date.now(),i=()=>{window.clearInterval(c),window.scrollTo(0,0),n();},c=window.setInterval(()=>{if(Date.now()-a>=r){i();return}window.scrollBy(0,s),o+=s;let u=Math.max(document.body?.scrollHeight||0,document.documentElement?.scrollHeight||0);o>=u+window.innerHeight&&i();},120);});},t);}async function et(e){ye();let t=W(e,k),r=await Ye.send(new GetObjectCommand({Bucket:$,Key:t}));if(!r.Body)throw new Error(`S3 object has no body: ${t}`);return {body:await r.Body.transformToString("utf8"),contentType:r.ContentType?.trim()||null}}async function lr(e){return (await et(e)).body}async function ne(e){return JSON.parse(await lr(e))}async function oe(e,t,r){ye();let n=W(e,k),o=typeof t=="string"?Buffer.from(t,"utf8"):t,s=await Ye.send(new PutObjectCommand({Bucket:$,Key:n,Body:o,ContentType:r,Metadata:{sha256:_(o)}}));return {bucket:$,key:n,sha256:_(o),bytes:o.byteLength,contentType:r,...s.ETag?{etag:s.ETag}:{},...s.VersionId?{versionId:s.VersionId}:{}}}async function ur(e,t){return await oe(e,`${JSON.stringify(t,null,2)}
|
|
5
|
+
`);}catch{}}function ze(){qe||(qe=true,process.on("uncaughtExceptionMonitor",(e,t)=>{we("runtime.uncaught-exception",{origin:t,...He(e)});}),process.on("exit",e=>{we("runtime.process-exit",{exitCode:e});}));}async function g(e,t,r={},n="info"){try{B=Fe(t);let o=null;try{o=await Ke();}catch(a){r={...r,resourceSnapshotError:a instanceof Error?a.message:String(a)};}let s=JSON.stringify({message:"Remote worker checkpoint.",event:e,...B,...r,...o?{resources:o}:{}});console[n](s);}catch(o){we("checkpoint.write-failed",{checkpointEvent:e,...He(o)});}}function ee(e){B=Fe(e);}function Ge(){B={};}var $=String(process.env.PUBLISHER_WORKSPACE_BUCKET??"").trim(),k=L(process.env.PUBLISHER_WORKSPACE_PREFIX??""),te=String(process.env.PUBLISHER_ALLOWED_OPERATION??"").trim(),M=String(process.env.PUBLISHER_EXPORTER_VERSION??"unknown").trim(),N=String(process.env.PUBLISHER_PROXY_URL??"").trim(),nr=or(process.env.PUBLISHER_ALLOWED_TARGETS??"[]"),Ye=new S3Client({}),Je=new Map,b=null,D=false;ze();function or(e){try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(r=>{if(!r||typeof r!="object")return !1;let n=r;return ["id","bucketName","prefix","region"].every(o=>typeof n[o]=="string")}).map(r=>({...r,prefix:L(r.prefix)})):[]}catch{return []}}function ye(){if(!$)throw new Error("PUBLISHER_WORKSPACE_BUCKET is required.")}async function Re(e,t){try{let r=await De();r.length>0&&await g(`browser.stale-processes-killed.${t}`,e,{killedProcesses:r.length,killedProcessIds:r},"warn");let n=await Ne();n.length>0&&await g(`browser.temp-entries-removed.${t}`,e,{removedEntries:n.length,removedEntryNames:n.slice(0,20)}),await _e();}catch(r){if(await g(`browser.profile-cleanup-failed.${t}`,e,{error:r instanceof Error?r.message:String(r)},"error"),t==="before-launch")throw r}}async function sr(e){if(b){let r=await b.catch(()=>null);if(r?.isConnected())return r}await g("browser.launch-preparing",e),await Re(e,"before-launch"),await g("browser.launch-started",e);let t=chromium.launch({headless:true,args:["--no-sandbox","--disable-setuid-sandbox","--no-zygote","--disable-gpu"],...N?{proxy:{server:N}}:{}});b=t;try{let r=await t;return r.once("disconnected",()=>{b===t&&(b=null);let n=D;ee(e),g("browser.disconnected",e,{expected:n},n?"info":"error");}),await g("browser.launch-succeeded",e),r}catch(r){throw b===t&&(b=null),await g("browser.launch-failed",e,{error:r instanceof Error?r.message:String(r)},"error"),r}}async function Qe(e){let t=b;if(b=null,t){let r=await t.catch(()=>null);r&&(D=true,await r.close().catch(async n=>{await g("browser.close-failed",e,{error:n instanceof Error?n.message:String(n)},"warn");}),D=false);}await Re(e,"after-close");}async function ir(e,t){let r;for(let n=1;n<=2;n+=1){let o=await sr({...t,attempt:n}),s=null;try{s=await o.newContext({viewport:e.options.viewport,ignoreHTTPSErrors:e.options.ignoreHttpsErrors,javaScriptEnabled:e.options.javaScriptEnabled,serviceWorkers:"block",userAgent:"WPSuiteStaticPublisher/remote-worker-v1"}),e.options.javaScriptEnabled&&await ar(s);let a=await xe(s);return {context:s,page:await s.newPage(),networkPolicyViolation:a.getViolation}}catch(a){r=a,await s?.close().catch(()=>{}),b=null,D=true,await o.close().catch(()=>{}),D=false,await Re({...t,attempt:n},"after-close");}}throw r instanceof Error?r:new Error(`Unable to create a Chromium page: ${String(r)}`)}async function ar(e){await e.addInitScript(()=>{Object.defineProperty(window,"__WPSUITE_STATIC_EXPORT__",{value:true,writable:false,configurable:true});let t=r=>{if(r==null||String(r)==="")return true;try{let n=new URL(String(r),window.location.href),o=new URL(window.location.href);return n.hash="",o.hash="",n.href===o.href}catch{return false}};try{let r=window.location.assign.bind(window.location),n=window.location.replace.bind(window.location);Object.defineProperty(window.location,"assign",{configurable:!0,value:o=>{if(!t(o))return r(o)}}),Object.defineProperty(window.location,"replace",{configurable:!0,value:o=>{if(!t(o))return n(o)}}),Object.defineProperty(window.location,"reload",{configurable:!0,value:()=>{}});}catch{}});}async function cr(e,t){await e.evaluate(async r=>{await new Promise(n=>{let o=0,s=700,a=Date.now(),i=()=>{window.clearInterval(c),window.scrollTo(0,0),n();},c=window.setInterval(()=>{if(Date.now()-a>=r){i();return}window.scrollBy(0,s),o+=s;let u=Math.max(document.body?.scrollHeight||0,document.documentElement?.scrollHeight||0);o>=u+window.innerHeight&&i();},120);});},t);}async function et(e){ye();let t=W(e,k),r=await Ye.send(new GetObjectCommand({Bucket:$,Key:t}));if(!r.Body)throw new Error(`S3 object has no body: ${t}`);return {body:await r.Body.transformToString("utf8"),contentType:r.ContentType?.trim()||null}}async function lr(e){return (await et(e)).body}async function ne(e){return JSON.parse(await lr(e))}async function oe(e,t,r){ye();let n=W(e,k),o=typeof t=="string"?Buffer.from(t,"utf8"):t,s=await Ye.send(new PutObjectCommand({Bucket:$,Key:n,Body:o,ContentType:r,Metadata:{sha256:_(o)}}));return {bucket:$,key:n,sha256:_(o),bytes:o.byteLength,contentType:r,...s.ETag?{etag:s.ETag}:{},...s.VersionId?{versionId:s.VersionId}:{}}}async function ur(e,t){return await oe(e,`${JSON.stringify(t,null,2)}
|
|
6
6
|
`,"application/json; charset=utf-8")}async function dr(e){try{let t=await ne(e);return t.response??t}catch(t){if(t.name==="NoSuchKey"||t.$metadata?.httpStatusCode===404)return null;throw t}}function re(e){return [...new Set(e)].filter(t=>{try{let r=new URL(t);return (r.protocol==="http:"||r.protocol==="https:")&&!r.username&&!r.password}catch{return false}}).sort()}async function pr(e,t,r,n){let o=null,s=null,a,i=new Set;try{let c=await ir(e,n);o=c.context,s=c.page,a=c.networkPolicyViolation,s.on("request",f=>i.add(f.url()));let u=await s.goto(t,{waitUntil:"domcontentloaded",timeout:e.options.navigationTimeoutMs});e.options.readiness.waitForSelector&&await s.waitForSelector(e.options.readiness.waitForSelector,{timeout:e.options.readiness.timeoutMs}).catch(()=>{}),e.options.javaScriptEnabled&&e.options.readiness.waitForFunction&&await s.waitForFunction(e.options.readiness.waitForFunction,void 0,{timeout:e.options.readiness.timeoutMs}).catch(()=>{}),e.options.javaScriptEnabled?await cr(s,e.options.autoScrollTimeoutMs):await s.waitForLoadState("load",{timeout:e.options.readiness.timeoutMs}).catch(()=>{}),e.options.readiness.fallbackWaitMs>0&&await s.waitForTimeout(e.options.readiness.fallbackWaitMs);let l=a?.();if(l)throw l;let d=await s.evaluate(()=>{let f=(I,tt)=>{let se=[];for(let rt of document.querySelectorAll(I))for(let be of tt){let ie=rt.getAttribute(be);if(ie)if(be.includes("srcset"))for(let nt of ie.split(",")){let Ee=nt.trim().split(/\s+/,1)[0];Ee&&se.push(Ee);}else se.push(ie);}return se},j=I=>{try{return new URL(I,document.baseURI).href}catch{return null}};return {links:f("a[href]",["href"]).map(j).filter(I=>I!==null),assets:f("img,script,link,source,video,audio,iframe,[data-src],[data-href],[data-resource-url]",["src","href","srcset","data-src","data-srcset","data-href","data-resource-url","poster"]).map(j).filter(I=>I!==null)}});await s.evaluate(()=>{document.querySelectorAll("#wpsuite-consent-root").forEach(f=>f.remove()),document.documentElement.classList.remove("wpsuite-consent-scroll-locked"),document.body.classList.remove("wpsuite-consent-scroll-locked");});let m=await s.content(),p=a();if(p)throw p;let y=new URL(t),R=re(d.links).filter(f=>{let j=new URL(f);return j.hash="",j.origin===y.origin}),A=T(z(k,e.jobId,e.taskId),"pages",`${String(r).padStart(4,"0")}-${_(t).slice(0,24)}.html`),q=Q(u?.headers()["content-type"],s.url()||t,"text/html; charset=utf-8"),F=await oe(A,m,q),h=(await o.cookies()).map(f=>({name:f.name,domain:f.domain,path:f.path,expires:f.expires,httpOnly:f.httpOnly,secure:f.secure,sameSite:f.sameSite,..."partitionKey"in f?{partitioned:!0}:{}})),H=u?.status()??null;return {requestedUrl:t,finalUrl:s?.url()||null,outcome:H!==null&&H>=400?"http-error":"rendered",httpStatus:H,contentType:q,html:F,discoveredPages:R,discoveredAssets:re([...d.assets,...ue(s.url()||t,m,u?.headers()["content-type"]??"text/html")]),networkUrls:re([...i]),cookies:h}}catch(c){return {requestedUrl:t,finalUrl:s?.url()||null,outcome:"failed",httpStatus:null,contentType:null,html:null,discoveredPages:[],discoveredAssets:[],networkUrls:re([...i]),cookies:[],error:c instanceof Error?c.message:String(c)}}finally{await o?.close().catch(()=>{});}}function mr(e){return e.outcome==="failed"&&typeof e.error=="string"&&/(?:target page, context or browser has been closed|browser closed|connection closed)/i.test(e.error)}async function gr(e,t,r,n){let o=null;for(let s=1;s<=2;s+=1){let a={requestId:t.awsRequestId,jobId:e.jobId,taskId:e.taskId,operation:e.operation,pageIndex:n,url:r,attempt:s,remainingTimeMs:t.getRemainingTimeInMillis?.()};ee(a),await g("render.page-started",a);let i=await pr(e,r,n,a);o=i;let c=mr(i);if(c&&await Qe(a),await g(c?"render.page-browser-closed":"render.page-finished",{...a,remainingTimeMs:t.getRemainingTimeInMillis?.()},{outcome:i.outcome,httpStatus:i.httpStatus,...i.error?{error:i.error.split(`
|
|
7
7
|
`,1)[0]}:{}},i.outcome==="failed"?"warn":"info"),!c||s===2)return i;await g("render.page-retry-with-fresh-browser",a,{nextAttempt:s+1},"warn");}if(o)return o;throw new Error(`Remote render did not produce a result for ${r}.`)}function fr(e,t){let r=t.toLowerCase();if(r.startsWith("text/")||r.includes("javascript")||r.includes("json")||r.includes("xml")||r.includes("svg"))return true;try{return /\.(?:css|js|mjs|json|xml|xsl|svg|txt|map|html?)$/i.test(new URL(e).pathname)}catch{return false}}async function hr(e,t,r){let n=t;for(let o=0;o<=5;o+=1){await le(n,"asset request");let s=await e.get(n,{timeout:r,failOnStatusCode:false,maxRedirects:0}),a=s.status();if(a<300||a>=400)return s;let i=s.headers().location;if(!i)return s;if(o===5)throw await s.dispose(),new Error("Asset request exceeded five redirects.");n=new URL(i,n).toString(),await s.dispose();}throw new Error("Asset redirect handling failed.")}async function wr(e,t,r){if(!Array.isArray(e.urls)||e.urls.length<1||e.urls.length>20)throw new Error("Asset tasks require between 1 and 20 URLs.");let n=await request.newContext({ignoreHTTPSErrors:e.options.ignoreHttpsErrors,userAgent:"WPSuiteStaticPublisher/remote-asset-worker-v1",...N?{proxy:{server:N}}:{}}),o=[],s=async i=>{o.push(i);let c=o.filter(u=>u.outcome==="failed"||u.outcome==="deferred").length;await r.updated(o.length-c,c);};try{for(let i=0;i<e.urls.length;i+=1){let c=e.urls[i],u=t.getRemainingTimeInMillis?.();if(u!==void 0&&u<3e4){await s({requestedUrl:c,finalUrl:null,outcome:"deferred",httpStatus:null,contentType:null,cacheControl:null,lastModified:null,object:null,discoveredAssets:[],error:"Worker stopped accepting assets because less than 30 seconds remained."});continue}let l=null;try{l=await hr(n,c,e.options.timeoutMs);let d=l.status(),m=l.headers(),p=l.url()||c;if(d<200||d>=300){await s({requestedUrl:c,finalUrl:p,outcome:"http-error",httpStatus:d,contentType:m["content-type"]??null,cacheControl:m["cache-control"]??null,lastModified:m["last-modified"]??null,object:null,discoveredAssets:[],error:`Asset returned HTTP ${d}.`});continue}let y=await l.body(),R=Q(m["content-type"],p,"application/octet-stream"),A=await oe(T(z(k,e.jobId,e.taskId),"assets",`${String(i).padStart(4,"0")}-${_(c).slice(0,24)}.bin`),y,R);await s({requestedUrl:c,finalUrl:p,outcome:"fetched",httpStatus:d,contentType:R,cacheControl:m["cache-control"]??null,lastModified:m["last-modified"]??null,object:A,discoveredAssets:fr(p,R)?ue(p,new TextDecoder("utf8").decode(y),R):[]});}catch(d){await s({requestedUrl:c,finalUrl:l?.url()??null,outcome:"failed",httpStatus:l?.status()??null,contentType:l?.headers()["content-type"]??null,cacheControl:l?.headers()["cache-control"]??null,lastModified:l?.headers()["last-modified"]??null,object:null,discoveredAssets:[],error:d instanceof Error?d.message:String(d)});}finally{await l?.dispose().catch(()=>{});}}}finally{await n.dispose();}let a=o.filter(i=>i.outcome==="failed"||i.outcome==="deferred").length;return {response:{schemaVersion:P,operation:"asset",jobId:e.jobId,taskId:e.taskId,status:a>0?"partial":"succeeded",completedItems:o.length-a,failedItems:a,exporterVersion:M},detail:{assets:o}}}async function yr(e,t,r){if(!Array.isArray(e.urls)||e.urls.length<1||e.urls.length>20)throw new Error("Render tasks require between 1 and 20 URLs.");let n=new URL(e.sourceOrigin).origin,o=[];for(let a=0;a<e.urls.length;a+=1){let i=e.urls[a];if(!i)continue;let c=t.getRemainingTimeInMillis?.();if(c!==void 0&&c<6e4){o.push({requestedUrl:i,finalUrl:null,outcome:"deferred",httpStatus:null,contentType:null,html:null,discoveredPages:[],discoveredAssets:[],networkUrls:[],cookies:[],error:"Worker stopped accepting URLs because less than 60 seconds remained."}),await r.updated(o.filter(d=>d.outcome!=="failed"&&d.outcome!=="deferred").length,o.filter(d=>d.outcome==="failed"||d.outcome==="deferred").length);continue}let u=new URL(i);if(u.origin!==n)throw new Error(`Primary render URL is outside sourceOrigin: ${i}`);o.push(await gr(e,t,u.toString(),a));let l=o.filter(d=>d.outcome==="failed"||d.outcome==="deferred").length;await r.updated(o.length-l,l);}let s=o.filter(a=>a.outcome==="failed"||a.outcome==="deferred").length;return {response:{schemaVersion:P,operation:"render",jobId:e.jobId,taskId:e.taskId,status:s>0?"partial":"succeeded",completedItems:o.length-s,failedItems:s,exporterVersion:M},detail:{pages:o}}}async function Rr(e,t){if(!Array.isArray(e.items)||e.items.length<1||e.items.length>500)throw new Error("Rewrite tasks require between 1 and 500 objects.");let n={...await ne(e.configKey),outputDir:"/workspace"},o=await ne(e.assetMapKey),s=e.previousAssetMapKey?await ne(e.previousAssetMapKey):{},a=[];for(let i of e.items){let c=W(i.inputKey,k),u=W(i.outputKey,k),l=await et(c),d=l.body,m=`/workspace/${i.relativePath.replace(/^\/+/,"")}`,p=$e(d,n,o,m,s),y=Q(i.contentType||l.contentType,i.relativePath,"text/plain; charset=utf-8"),R=await oe(u,p,y);a.push({inputKey:c,outputKey:u,changed:p!==d,output:R}),await t.updated(a.length,0);}return {response:{schemaVersion:P,operation:"rewrite",jobId:e.jobId,taskId:e.taskId,status:"succeeded",completedItems:a.length,failedItems:0,exporterVersion:M},detail:{objects:a}}}function br(e,t){return `${e}/${t.split("/").map(r=>encodeURIComponent(r)).join("/")}`}async function Er(e,t){if(!Array.isArray(e.items)||e.items.length>1e3)throw new Error("Deploy copy tasks accept at most 1000 objects.");let r=nr.find(l=>l.id===e.targetId);if(!r)throw new Error(`Unknown deployment target: ${e.targetId}`);let n=Je.get(r.region);n||(n=new S3Client({region:r.region}),Je.set(r.region,n));let o=[];for(let l of e.items){let d=W(l.sourceKey,k),m=T(r.prefix,l.targetRelativeKey);try{let p=await n.send(new HeadObjectCommand({Bucket:r.bucketName,Key:m})).catch(h=>{if((h&&typeof h=="object"&&"$metadata"in h?Number(h.$metadata?.httpStatusCode):0)===404||h?.name==="NotFound")return null;throw h}),y=String(p?.CacheControl??"").replace(/\s+/g,"")===l.cacheControl.replace(/\s+/g,""),R=ge(p?.ContentType)===ge(l.contentType),A=p?.Metadata?.["wpsuite-sha256"]===l.sha256,q=!!l.normalizedSha256&&p?.Metadata?.["wpsuite-normalized-sha256"]===l.normalizedSha256;if(y&&R&&(A||q)){o.push({sourceKey:d,targetKey:m,status:"skipped"}),await t.updated(o.filter(h=>h.status!=="failed").length,o.filter(h=>h.status==="failed").length);continue}let F=await n.send(new CopyObjectCommand({Bucket:r.bucketName,Key:m,CopySource:br($,d),MetadataDirective:"REPLACE",ContentType:l.contentType,CacheControl:l.cacheControl,Metadata:{"wpsuite-sha256":l.sha256,...l.normalizedSha256?{"wpsuite-normalized-sha256":l.normalizedSha256}:{}}}));o.push({sourceKey:d,targetKey:m,status:"copied",...F.CopyObjectResult?.ETag?{etag:F.CopyObjectResult.ETag}:{}}),await t.updated(o.filter(h=>h.status!=="failed").length,o.filter(h=>h.status==="failed").length);}catch(p){o.push({sourceKey:d,targetKey:m,status:"failed",error:p instanceof Error?p.message:String(p)}),await t.updated(o.filter(y=>y.status!=="failed").length,o.filter(y=>y.status==="failed").length);}}let a=(e.deleteRelativeKeys??[]).map(l=>T(r.prefix,l)),i=[],c=[];if(a.length>0){let l=await n.send(new DeleteObjectsCommand({Bucket:r.bucketName,Delete:{Objects:a.map(d=>({Key:d})),Quiet:false}}));i.push(...(l.Deleted??[]).flatMap(d=>d.Key?[d.Key]:[])),c.push(...(l.Errors??[]).map(d=>({key:d.Key??"",error:d.Message??d.Code??"S3 deletion failed"}))),await t.updated(o.filter(d=>d.status!=="failed").length+i.length,o.filter(d=>d.status==="failed").length+c.length);}let u=o.filter(l=>l.status==="failed").length+c.length;return {response:{schemaVersion:P,operation:"deploy-copy",jobId:e.jobId,taskId:e.taskId,status:u>0?"partial":"succeeded",completedItems:o.filter(l=>l.status!=="failed").length+i.length,failedItems:u,exporterVersion:M},detail:{objects:o,deletedKeys:i,deleteErrors:c,targetId:r.id}}}async function Xe(e,t,r){if(e.operation==="health")return {response:{schemaVersion:P,operation:"health",jobId:e.jobId,taskId:e.taskId,status:"succeeded",completedItems:1,failedItems:0,exporterVersion:M},detail:{allowedOperation:te,workspaceBucket:$,workspacePrefix:k,proxyConfigured:!!N}};if(te&&te!==e.operation)throw new Error(`Function is configured for ${te}, not ${e.operation}.`);if(!r)throw new Error("Remote worker progress reporter is required.");return e.operation==="render"?await yr(e,t,r):e.operation==="asset"?await wr(e,t,r):e.operation==="rewrite"?await Rr(e,r):await Er(e,r)}async function yn(e,t={}){let r=Pe(e),n=setInterval(()=>{},1e3),o={requestId:t.awsRequestId,jobId:r.jobId,taskId:r.taskId,operation:r.operation,remainingTimeMs:t.getRemainingTimeInMillis?.()};ee(o),await g("invocation.started",o,{exporterVersion:M});try{if(r.operation==="health"){let c=(await Xe(r,t)).response;return await g("invocation.completed",{...o,remainingTimeMs:t.getRemainingTimeInMillis?.()},{status:c.status}),c}ye();let s=T(z(k,r.jobId,r.taskId),"result.json"),a=await dr(s),i=new Y(r,t.awsRequestId);if(a)return await i.completed(a),await g("invocation.completed-from-existing-result",{...o,remainingTimeMs:t.getRemainingTimeInMillis?.()},{status:a.status}),a;await i.started();try{let c=await Xe(r,t,i),u={...c.response,resultKey:s};return await ur(s,{schemaVersion:P,response:u,detail:c.detail,completedAt:new Date().toISOString(),requestId:t.awsRequestId??null}),await i.completed(u),await g("invocation.completed",{...o,remainingTimeMs:t.getRemainingTimeInMillis?.()},{status:u.status,completedItems:u.completedItems,failedItems:u.failedItems}),u}catch(c){throw await i.failed(),c}}catch(s){throw await g("invocation.failed",{...o,remainingTimeMs:t.getRemainingTimeInMillis?.()},{errorName:s instanceof Error?s.name:"UnknownError",error:s instanceof Error?s.message:String(s)},"error"),s}finally{await g("invocation.cleanup-started",{...o,remainingTimeMs:t.getRemainingTimeInMillis?.()}),r.operation==="render"&&await Qe({...o,remainingTimeMs:t.getRemainingTimeInMillis?.()}),await g("invocation.cleanup-finished",{...o,remainingTimeMs:t.getRemainingTimeInMillis?.()}),clearInterval(n),Ge();}}export{yn as handler};
|
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.71",
|
|
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.",
|