diff --git a/knip.json b/knip.json index 20bcb5ff2d..413b740578 100644 --- a/knip.json +++ b/knip.json @@ -385,6 +385,7 @@ }, "packages/code-runtime/code-runtime-subprocess": { "entry": [ + "src/runner.ts", "tests/**/*.spec.ts", "tests/**/*.e2e.ts" ], diff --git a/packages/util/atomic-write/src/runner-source.generated.ts b/packages/util/atomic-write/src/runner-source.generated.ts index d40c77783c..8592fa2399 100644 --- a/packages/util/atomic-write/src/runner-source.generated.ts +++ b/packages/util/atomic-write/src/runner-source.generated.ts @@ -3,4 +3,4 @@ * Do not edit by hand; run `pnpm run gen-code-runtime-runner`. */ -export const CODE_RUNNER_SOURCE = "import{Buffer as e}from\"node:buffer\";import{fork as t}from\"node:child_process\";import{createInterface as n}from\"node:readline\";import{inspect as r}from\"node:util\";import{fileURLToPath as i}from\"node:url\";import{Worker as a,isMainThread as o,parentPort as s,workerData as c}from\"node:worker_threads\";const l=Reflect.apply,u=Array.isArray,d=Buffer,f=Reflect.get(Buffer,`byteLength`),ee=Object.create,p=Object.defineProperty,te=Object.keys,ne=String,re=Reflect.get(String.prototype,`charCodeAt`),ie=Reflect.get(String.prototype,`codePointAt`),m=Reflect.get(String.prototype,`slice`);function h(e){let t=ee(null);return t.value=e,t}function ae(e,t,n){let r=h(n);r.enumerable=!0,r.configurable=!0,r.writable=!0,p(e,t,r)}function g(e){return l(f,d,[e,`utf8`])}function _(e,t){ae(e,e.length,t)}function oe(e){if(e.length===0)return;let t=e.length-1,n=e[t];return p(e,`length`,h(t)),n}function se(e,t){return l(m,e,[t,t+(l(ie,e,[t])>65535?2:1)])}function ce(e){if(e.length===2)return 4;if(e===`\"`||e===`\\\\`)return 2;let t=l(re,e,[0]);return t>=55296&&t<=57343?6:t<32?t===8||t===9||t===10||t===12||t===13?2:6:g(e)}function v(e,t){if(t<2)return;let n=2;for(let r=0;rt)return;r+=i.length}return n}function y(e,t){let n=0,r=e=>(n+=e,n<=t),i=[{kind:`value`,value:e}];for(let e=oe(i);e!==void 0;e=oe(i)){if(e.kind===`value`){let a=e.value;if(a===null){if(!r(4))return}else if(typeof a==`string`){let e=v(a,t-n);if(e===void 0)return;n+=e}else if(typeof a==`number`){if(!r(g(ne(a))))return}else if(typeof a==`boolean`){if(!r(a?4:5))return}else if(u(a)){if(!r(2))return;a.length>0&&_(i,{kind:`array`,value:a,index:0})}else{if(!r(2))return;let e=te(a);e.length>0&&_(i,{kind:`object`,value:a,keys:e,index:0})}continue}if(e.index>0&&!r(1))return;if(e.kind===`array`){let t=e.value[e.index];if(t===void 0)return;e.index+1t)break;n+=o,r+=a.length,i+=a.length}return r===e.length?e:l(m,e,[0,r])}const ue=Reflect.get(Function.prototype,`toString`),b=Reflect.get(Reflect,`apply`),x=Error,S=Set,C=Array.isArray,de=Array.prototype,w=Number.isFinite,fe=Number.isSafeInteger,pe=Object.create,me=Object.defineProperty,he=Object.getOwnPropertyDescriptor,T=Object.getPrototypeOf,ge=Object.hasOwn,E=Object.is,_e=Object.keys,D=Object.prototype,ve=Reflect.get(D,`propertyIsEnumerable`),O=Reflect.ownKeys,ye=Reflect.get(Set.prototype,`add`),be=Reflect.get(Set.prototype,`delete`),xe=Reflect.get(Set.prototype,`has`);function k(e){let t=pe(null);return t.value=e,t}function A(e,t,n){let r=k(n);r.enumerable=!0,r.configurable=!0,r.writable=!0,me(e,t,r)}function j(e,t){A(e,e.length,t)}function M(e){if(e.length===0)return;let t=e.length-1,n=e[t];return me(e,`length`,k(t)),n}function N(e,t){return b(xe,e,[t])}function P(e,t){b(ye,e,[t])}function Se(e,t){b(be,e,[t])}function F(e,t){let n=he(e,`constructor`)?.value;if(typeof n!=`function`)return!1;try{return n.name===t&&n.prototype===e&&b(ue,n,[])===`function ${t}() { [native code] }`}catch{return!1}}function I(e){return T(e)===null&&F(e,`Object`)}function L(e){let t=T(e);if(t===de)return!0;if(!C(t)||!F(t,`Array`))return!1;let n=T(t);return typeof n==`object`&&!!n&&I(n)}function R(e){let t=T(e);return t===null||t===D||typeof t==`object`&&I(t)}function z(e){let t=O(e);for(let n=0;n{e.kind===`root`?n=t:e.kind===`array`?A(e.target,e.index,t):A(e.target,e.key,t)},i=[{kind:`visit`,value:e,destination:{kind:`root`}}];for(let e=M(i);e!==void 0;e=M(i)){if(e.kind===`leave`){Se(t,e.source);continue}if(e.kind===`array-item`){if(!ge(e.source,e.index))return;j(i,{kind:`visit`,value:e.source[e.index],destination:{kind:`array`,target:e.target,index:e.index}});continue}if(e.kind===`object-property`){j(i,{kind:`visit`,value:e.source[e.key],destination:{kind:`object`,target:e.target,key:e.key}});continue}let n=e.value;if(n===null){r(e.destination,null);continue}if(typeof n==`boolean`||typeof n==`string`){r(e.destination,n);continue}if(typeof n==`number`){if(!w(n)||E(n,-0))return;r(e.destination,n);continue}if(typeof n!=`object`||N(t,n))return;if(C(n)){if(!L(n))return;let a=n.length;if(O(n).length!==a+1)return;let o=[];r(e.destination,o),P(t,n),j(i,{kind:`leave`,source:n});for(let e=a-1;e>=0;e--)j(i,{kind:`array-item`,source:n,index:e,target:o});continue}if(!R(n))return;let a=z(n);if(a===void 0)return;let o={};r(e.destination,o),P(t,n),j(i,{kind:`leave`,source:n});for(let e=a.length-1;e>=0;e--){let t=a[e];if(t===void 0)return;j(i,{kind:`object-property`,source:n,key:t,target:o})}}return n}function V(e){let t=[],n=[e];for(let e=M(n);e!==void 0;e=M(n)){if(e===null||typeof e==`boolean`||typeof e==`number`||typeof e==`string`){j(t,e);continue}if(C(e)){j(t,{kind:`array`,length:e.length});for(let t=e.length-1;t>=0;t--){let r=e[t];if(r===void 0)throw new x(`cannot encode a sparse JSON array`);j(n,r)}continue}let r=_e(e);j(t,{kind:`object`,keys:r});for(let t=r.length-1;t>=0;t--){let i=r[t];if(i===void 0)throw new x(`cannot encode a missing JSON object key`);let a=e[i];if(a===void 0)throw new x(`cannot encode an undefined JSON object property`);j(n,a)}}return t}function H(e){if(!L(e)||O(e).length!==e.length+1)return!1;for(let t=0;t=0?{kind:`array`,length:e}:void 0}if(n.kind===`object`){if(t.length!==2||!U(t,`kind`)||!U(t,`keys`))return;let e=n.keys;if(!C(e)||!H(e))return;let r=new S,i=[],a=e;for(let e=0;e{let t=n[n.length-1];if(!t)return i?!1:(r=e,i=!0,!0);if(t.index>=(t.kind===`array`?t.length:t.keys.length))return!1;if(t.kind===`array`)j(t.target,e);else{let n=t.keys[t.index];if(n===void 0)return!1;A(t.target,n,e)}return t.index+=1,!0};for(let e=0;ea)return;let e=[];i=e,n.length>0&&(o={kind:`array`,target:e,length:n.length,index:0})}else{if(n.keys.length>a)return;let e={};i=e,n.keys.length>0&&(o={kind:`object`,target:e,keys:n.keys,index:0})}}if(!a(i))return;for(o&&j(n,o);n.length>0;){let e=n[n.length-1];if(e===void 0||e.index<(e.kind===`array`?e.length:e.keys.length))break;M(n)}}return n.length===0?r:void 0}catch{return}}const G=Error,we=Object.create,Te=Object.defineProperty;function K(e,t,n){let r=we(null);r.enumerable=!0,r.value=n,Te(e,t,r)}var Ee=class{bytes=2;entries=0;truncated=!1;sink;onLimit;maxBytes;constructor(e,t,n=()=>{}){this.maxBytes=e,this.sink=t,this.onLimit=n}push(e){if(this.truncated)return;let t=+(this.entries>0),n=this.maxBytes-this.bytes-t,r=v(e,n);if(r===void 0){this.truncated=!0;let r=le(e,n);if(r.length>0){let e=v(r,n);if(e===void 0)throw new G(`worker output ledger produced an oversized log prefix`);this.bytes+=e+t,this.entries+=1,this.sink(r)}this.onLimit();return}this.bytes+=r+t,this.entries+=1,this.sink(e)}remainingOutputBytes(){return this.maxBytes-this.bytes}};const De=[`log`,`info`,`warn`,`error`,`debug`];function Oe(e){let t=e=>e.map(e=>typeof e==`string`?e:r(e,Ae)).join(` `),n=Object.create(null);for(let r of De)n[r]=(...n)=>{e.push(t(n))};return n}function ke(e,t){let n=t.write;return t.write=(t,...n)=>{e.push(typeof t==`string`?t:String(t));let r=[n[0],n[1]].find(e=>typeof e==`function`);return r&&queueMicrotask(()=>{r(null)}),!0},()=>{t.write=n}}const Ae={depth:4,maxArrayLength:100,maxStringLength:1e4};function je(e,t,n=t){if(e===void 0)return{};let r;try{r=B(e)}catch{r=void 0}return r===void 0?Ne(`invalid-output`,`program completion must be lossless JSON`,t,n):y(r,t)===void 0?Me(n):{value:V(r)}}function Me(e){return{error:{kind:`output-limit`,message:`outer output exceeded ${e} bytes`}}}function Ne(e,t,n,r){return v(t,n)===void 0?Me(r):{error:{kind:e,message:t}}}function Pe(e,t,n=t){let r;try{let t=e instanceof G?e.stack??e.message:e;r=typeof t==`string`?t:String(t)}catch{r=`program threw an unrenderable value`}return Ne(`exception`,r,t,n)}function Fe(e){return class extends G{constructor(t,n){super(n),K(this,`name`,e.name),K(this,e.memberNameProperty,t)}}}function q(e,t,n){return e?new e(t,n):new G(n)}function Ie(e){let t=new Map;for(let n of e.namespaces)n.errorClass&&t.set(n.global,Fe(n.errorClass));return t}function Le(e,t){e.on(`message`,e=>{let n=t.get(e.id);if(n)if(t.delete(e.id),e.ok){let t=W(e.value);t===void 0?n.reject(new G(`binding resolution must be lossless JSON`)):n.resolve(t)}else n.reject(new G(e.message))})}function Re(e,t,n,r,i=Ie(e),a){return e.namespaces.map(({global:e,names:o})=>{let s=i.get(e),c=Object.create(null);for(let i of o)Object.defineProperty(c,i,{enumerable:!0,value:o=>{let c;try{c=B(o)}catch{c=void 0}if(c===void 0)return Promise.reject(q(s,i,`binding arguments must be lossless JSON`));let l={type:`call`,id:r.value,global:e,name:i,args:V(c)};return a!==void 0&&y(l,a)===void 0?Promise.reject(q(s,i,`binding arguments exceed maxFrameBytes`)):new Promise((e,a)=>{let o=r.value++;n.set(o,{resolve:e,reject:e=>{a(q(s,i,e.message))}});try{t.postMessage(l)}catch(e){n.delete(o),a(q(s,i,`binding arguments must be structured-cloneable: ${e instanceof G?e.message:String(e)}`))}})}});return c})}async function ze(e,t,n,r){let i=new Ee(t.maxOutputBytes,t=>{e.postMessage({type:`log`,text:t})},()=>{e.postMessage({type:`output-limit`})});ke(i,n.stdout),ke(i,n.stderr);let a=new Map;Le(e,a);let o={value:1},s=Ie(t),c=Re(t,e,a,o,s,r),l=[],u=[];for(let e of t.namespaces){if(!e.errorClass)continue;l.push(e.errorClass.name);let t=s.get(e.global);if(!t)throw new G(`missing binding error class for ${e.global}`);u.push(t)}let d=Oe(i),f;try{let e=(async()=>{}).constructor;f={type:`done`,...je(await new e(...t.namespaces.map(e=>e.global),...l,`console`,`'use strict';\\n${t.code}`)(...c,...u,d),i.remainingOutputBytes(),t.maxOutputBytes)}}catch(e){f={type:`done`,...Pe(e,i.remainingOutputBytes(),t.maxOutputBytes)}}e.postMessage(r!==void 0&&y(f,r)===void 0?{type:`output-limit`}:f)}function J(e){return e.readableEnded||e.destroyed?Promise.resolve():new Promise(t=>{let n=()=>{e.off(`end`,n),e.off(`close`,n),e.off(`error`,n),t()};e.once(`end`,n),e.once(`close`,n),e.once(`error`,n),(e.readableEnded||e.destroyed)&&n()})}const Be=new Set([`exception`,`timeout`,`abort`,`worker-exit`,`invalid-output`,`output-limit`]);let Y=0;function X(e){return typeof e==`object`&&e?e:void 0}function Z(t,n){try{let r=JSON.stringify(t);return typeof r==`string`&&e.byteLength(r)<=n?r:void 0}catch{return}}function Ve(e){process.stdout.write(e),process.stdout.write(`\n`)}function He(e){let t=Z(e,Y);return t===void 0?!1:(Ve(t),!0)}function Ue(e){let t=X(e);return t!==void 0&&typeof t.kind==`string`&&Be.has(t.kind)&&typeof t.message==`string`}function We(e){return Ue(e)&&(e.kind===`exception`||e.kind===`invalid-output`||e.kind===`output-limit`)}function Ge(e){let t=X(e);if(!(t===void 0||t.type!==`boot`||typeof t.code!=`string`||!Array.isArray(t.namespaces)||!Number.isSafeInteger(t.maxOutputBytes)||t.maxOutputBytes<4||!Number.isSafeInteger(t.maxFrameBytes)||t.maxFrameBytes{e.once(`exit`,()=>{t()})})}function $(){return{type:`done`,error:{kind:`worker-exit`,message:`code runtime bridge frame exceeded maxFrameBytes`}}}function Je(){let e=n({input:process.stdin,crlfDelay:1/0}),r,a=0,o=2,s=0,c=!1,l=t=>{if(c)return;let n=Z(t,Y)??Z($(),Y);c=!0,n!==void 0&&Ve(n);let i=r;r=void 0,(i===void 0?Promise.resolve():new Promise(e=>{setImmediate(e)}).then(async()=>{let e=J(i.stdout),t=J(i.stderr),n=qe(i);i.kill(`SIGKILL`),await Promise.all([n,e,t])})).catch(e=>{process.stderr.write(`dsh-code-runtime-subprocess controller cleanup error: ${String(e)}\\n`)}).then(()=>{e.close(),process.stdin.destroy()})},u=e=>{if(c)return;let t=+(s>0),n=v(e,a-o-t);if(n===void 0){l({type:`output-limit`});return}o+=n+t,s+=1,He({type:`log`,text:e})||l($())},d=e=>{a=e.maxOutputBytes,Y=e.maxFrameBytes,r=t(i(import.meta.url),[],{env:{DSH_CODE_RUNTIME_CONTROLLER:`1`},detached:!1,execArgv:[],stdio:[`ignore`,`pipe`,`pipe`,`ipc`]});let n=r;n.stdout.on(`data`,e=>{u(e.toString(`utf8`))}),n.stderr.on(`data`,e=>{u(e.toString(`utf8`))}),n.on(`message`,e=>{let t=X(e);if(t!==void 0){if(t.type===`log`&&typeof t.text==`string`){u(t.text);return}c||(t.type===`call`&&typeof t.id==`number`&&typeof t.global==`string`&&typeof t.name==`string`?He({type:`call`,id:t.id,global:t.global,name:t.name,args:Q(t.args)})||l($()):t.type===`output-limit`?l({type:`output-limit`}):t.type===`done`&&(t.error===void 0?l({type:`done`,...t.value===void 0?{}:{value:Q(t.value)}}):Ue(t.error)&&l({type:`done`,error:t.error})))}}),n.on(`error`,e=>{l({type:`done`,error:{kind:`worker-exit`,message:`remote controller error: ${e.message}`}})}),n.on(`exit`,e=>{c||l({type:`done`,error:{kind:`worker-exit`,message:`remote controller exited with code ${e} before completing`}})}),n.send(e,e=>{e!==null&&l({type:`done`,error:{kind:`worker-exit`,message:`remote controller boot failed: ${e.message}`}})})};e.on(`line`,e=>{let t;try{t=JSON.parse(e)}catch(e){process.stderr.write(`dsh-code-runtime-subprocess frame error: ${String(e)}\\n`),l({type:`done`,error:{kind:`worker-exit`,message:`remote runner received a malformed frame`}});return}if(r===void 0){let e=Ge(t);if(e===void 0){l({type:`done`,error:{kind:`worker-exit`,message:`remote runner received an invalid boot frame`}});return}d(e);return}let n=Ke(t);n!==void 0&&r.send(n,e=>{e!==null&&l({type:`done`,error:{kind:`worker-exit`,message:`remote controller reply failed: ${e.message}`}})})}),e.on(`close`,()=>{r!==void 0&&!c&&l({type:`done`,error:{kind:`abort`,message:`remote runner input closed`}})})}function Ye(){let e,t=!1,n,i=0,o=e=>process.send===void 0||i>0&&Z(e,i)===void 0?!1:(process.send(e),!0),s=r=>{if(t)return;t=!0,clearInterval(n);let a=i>0&&Z(r,i)===void 0?$():r,s=e;e=void 0,(s===void 0?Promise.resolve():new Promise(e=>{setImmediate(e)}).then(async()=>{let e=J(s.stdout),t=J(s.stderr);await Promise.all([s.terminate(),e,t])})).catch(e=>{o({type:`log`,text:`dsh-code-runtime-subprocess worker cleanup error: ${String(e)}\\n`})}).then(()=>{if(process.send===void 0){process.exitCode=1;return}process.send(a,()=>{process.connected&&process.disconnect()})})};process.on(`message`,c=>{if(e===void 0){let l=Ge(c);if(l===void 0){s({type:`done`,error:{kind:`worker-exit`,message:`remote controller received an invalid boot frame`}});return}i=l.maxFrameBytes,e=new a(new URL(import.meta.url),{workerData:l,env:{},execArgv:[],stdout:!0,stderr:!0,resourceLimits:{maxOldGenerationSizeMb:l.maxOldGenerationSizeMb}});let u=e;u.stdout.on(`data`,e=>{o({type:`log`,text:e.toString(`utf8`)})||s($())}),u.stderr.on(`data`,e=>{o({type:`log`,text:e.toString(`utf8`)})||s($())}),u.on(`message`,e=>{let t=X(e);t!==void 0&&(t.type===`call`&&typeof t.id==`number`&&typeof t.global==`string`&&typeof t.name==`string`?o({type:`call`,id:t.id,global:t.global,name:t.name,args:Q(t.args)})||s($()):t.type===`log`&&typeof t.text==`string`?o({type:`log`,text:t.text})||s($()):t.type===`output-limit`?s({type:`output-limit`}):t.type===`done`&&(t.error===void 0?s({type:`done`,...t.value===void 0?{}:{value:Q(t.value)}}):We(t.error)&&s({type:`done`,error:t.error})))}),u.on(`error`,e=>{s({type:`done`,error:{kind:`worker-exit`,message:`worker error: ${e.stack||e.message||r(e)}`}})}),u.on(`exit`,e=>{t||s({type:`done`,error:{kind:`worker-exit`,message:`worker exited with code ${e} before completing`}})}),n=setInterval(()=>{e!==void 0&&e.performance.eventLoopUtilization().active>l.computeMs&&s({type:`done`,error:{kind:`timeout`,message:`compute budget exhausted (${l.computeMs}ms busy)`}})},25);return}let l=Ke(c);l!==void 0&&e.postMessage(l)}),process.on(`disconnect`,()=>{e!==void 0&&!t&&e.terminate()})}if(o)process.env.DSH_CODE_RUNTIME_CONTROLLER===`1`?Ye():Je();else{if(s===null)throw Error(`remote worker requires parentPort`);let e=c;ze(s,e,{stdout:process.stdout,stderr:process.stderr},e.maxFrameBytes)}export{};" +export const CODE_RUNNER_SOURCE = "import{Buffer as e}from\"node:buffer\";import{fork as t}from\"node:child_process\";import{createInterface as n}from\"node:readline\";import{inspect as r}from\"node:util\";import{fileURLToPath as i}from\"node:url\";import{Worker as a,isMainThread as o,parentPort as s,workerData as c}from\"node:worker_threads\";const l=Reflect.apply,u=Array.isArray,d=Buffer,f=Reflect.get(Buffer,`byteLength`),ee=Object.create,p=Object.defineProperty,te=Object.keys,ne=String,re=Reflect.get(String.prototype,`charCodeAt`),ie=Reflect.get(String.prototype,`codePointAt`),m=Reflect.get(String.prototype,`slice`);function h(e){let t=ee(null);return t.value=e,t}function ae(e,t,n){let r=h(n);r.enumerable=!0,r.configurable=!0,r.writable=!0,p(e,t,r)}function g(e){return l(f,d,[e,`utf8`])}function _(e,t){ae(e,e.length,t)}function oe(e){if(e.length===0)return;let t=e.length-1,n=e[t];return p(e,`length`,h(t)),n}function se(e,t){return l(m,e,[t,t+(l(ie,e,[t])>65535?2:1)])}function ce(e){if(e.length===2)return 4;if(e===`\"`||e===`\\\\`)return 2;let t=l(re,e,[0]);return t>=55296&&t<=57343?6:t<32?t===8||t===9||t===10||t===12||t===13?2:6:g(e)}function v(e,t){if(t<2)return;let n=2;for(let r=0;rt)return;r+=i.length}return n}function y(e,t){let n=0,r=e=>(n+=e,n<=t),i=[{kind:`value`,value:e}];for(let e=oe(i);e!==void 0;e=oe(i)){if(e.kind===`value`){let a=e.value;if(a===null){if(!r(4))return}else if(typeof a==`string`){let e=v(a,t-n);if(e===void 0)return;n+=e}else if(typeof a==`number`){if(!r(g(ne(a))))return}else if(typeof a==`boolean`){if(!r(a?4:5))return}else if(u(a)){if(!r(2))return;a.length>0&&_(i,{kind:`array`,value:a,index:0})}else{if(!r(2))return;let e=te(a);e.length>0&&_(i,{kind:`object`,value:a,keys:e,index:0})}continue}if(e.index>0&&!r(1))return;if(e.kind===`array`){let t=e.value[e.index];if(t===void 0)return;e.index+1t)break;n+=o,r+=a.length,i+=a.length}return r===e.length?e:l(m,e,[0,r])}const ue=Reflect.get(Function.prototype,`toString`),b=Reflect.get(Reflect,`apply`),x=Error,S=Set,C=Array.isArray,de=Array.prototype,w=Number.isFinite,fe=Number.isSafeInteger,pe=Object.create,T=Object.defineProperty,me=Object.getOwnPropertyDescriptor,E=Object.getPrototypeOf,D=Object.hasOwn,O=Object.is,he=Object.keys,k=Object.prototype,ge=Reflect.get(k,`propertyIsEnumerable`),A=Reflect.ownKeys,_e=Reflect.get(Set.prototype,`add`),ve=Reflect.get(Set.prototype,`delete`),ye=Reflect.get(Set.prototype,`has`);function j(e){let t=pe(null);return t.value=e,t}function M(e,t,n){let r=j(n);r.enumerable=!0,r.configurable=!0,r.writable=!0,T(e,t,r)}function N(e,t){M(e,e.length,t)}function P(e){if(e.length===0)return;let t=e.length-1,n=e[t];return T(e,`length`,j(t)),n}function F(e,t){return b(ye,e,[t])}function I(e,t){b(_e,e,[t])}function be(e,t){b(ve,e,[t])}function L(e,t){let n=me(e,`constructor`)?.value;if(typeof n!=`function`)return!1;try{return n.name===t&&n.prototype===e&&b(ue,n,[])===`function ${t}() { [native code] }`}catch{return!1}}function R(e){return E(e)===null&&L(e,`Object`)}function z(e){let t=E(e);if(t===de)return!0;if(!C(t)||!L(t,`Array`))return!1;let n=E(t);return typeof n==`object`&&!!n&&R(n)}function B(e){let t=E(e);return t===null||t===k||typeof t==`object`&&R(t)}function V(e){let t=A(e);for(let n=0;n{e.kind===`root`?n=t:e.kind===`array`?M(e.target,e.index,t):M(e.target,e.key,t)},i=[{kind:`visit`,value:e,destination:{kind:`root`}}];for(let e=P(i);e!==void 0;e=P(i)){if(e.kind===`leave`){be(t,e.source);continue}if(e.kind===`array-item`){if(!D(e.source,e.index))return;N(i,{kind:`visit`,value:e.source[e.index],destination:{kind:`array`,target:e.target,index:e.index}});continue}if(e.kind===`object-property`){N(i,{kind:`visit`,value:e.source[e.key],destination:{kind:`object`,target:e.target,key:e.key}});continue}let n=e.value;if(n===null){r(e.destination,null);continue}if(typeof n==`boolean`||typeof n==`string`){r(e.destination,n);continue}if(typeof n==`number`){if(!w(n)||O(n,-0))return;r(e.destination,n);continue}if(typeof n!=`object`||F(t,n))return;if(C(n)){if(!z(n))return;let a=n.length;if(A(n).length!==a+1)return;let o=[];r(e.destination,o),I(t,n),N(i,{kind:`leave`,source:n});for(let e=a-1;e>=0;e--)N(i,{kind:`array-item`,source:n,index:e,target:o});continue}if(!B(n))return;let a=V(n);if(a===void 0)return;let o={};r(e.destination,o),I(t,n),N(i,{kind:`leave`,source:n});for(let e=a.length-1;e>=0;e--){let t=a[e];if(t===void 0)return;N(i,{kind:`object-property`,source:n,key:t,target:o})}}return n}function U(e){let t=[],n=[e];for(let e=P(n);e!==void 0;e=P(n)){if(e===null||typeof e==`boolean`||typeof e==`number`||typeof e==`string`){N(t,e);continue}if(C(e)){N(t,{kind:`array`,length:e.length});for(let t=e.length-1;t>=0;t--){let r=e[t];if(r===void 0)throw new x(`cannot encode a sparse JSON array`);N(n,r)}continue}let r=he(e);N(t,{kind:`object`,keys:r});for(let t=r.length-1;t>=0;t--){let i=r[t];if(i===void 0)throw new x(`cannot encode a missing JSON object key`);let a=e[i];if(a===void 0)throw new x(`cannot encode an undefined JSON object property`);N(n,a)}}return t}function xe(e){if(!z(e)||A(e).length!==e.length+1)return!1;for(let t=0;t=0?{kind:`array`,length:e}:void 0}if(n.kind===`object`){if(t.length!==2||!W(t,`kind`)||!W(t,`keys`))return;let e=n.keys;if(!C(e)||!xe(e))return;let r=new S,i=[],a=e;for(let e=0;e{let t=n[n.length-1];if(!t)return i?!1:(r=e,i=!0,!0);if(t.index>=(t.kind===`array`?t.length:t.keys.length))return!1;if(t.kind===`array`)N(t.target,e);else{let n=t.keys[t.index];if(n===void 0)return!1;M(t.target,n,e)}return t.index+=1,!0};for(let e=0;ea)return;let e=[];i=e,n.length>0&&(o={kind:`array`,target:e,length:n.length,index:0})}else{if(n.keys.length>a)return;let e={};i=e,n.keys.length>0&&(o={kind:`object`,target:e,keys:n.keys,index:0})}}if(!a(i))return;for(o&&N(n,o);n.length>0;){let e=n[n.length-1];if(e===void 0||e.index<(e.kind===`array`?e.length:e.keys.length))break;P(n)}}return n.length===0?r:void 0}catch{return}}const K=Error,Ce=Object.create,we=Object.defineProperty;function Te(e,t,n){let r=Ce(null);r.enumerable=!0,r.value=n,we(e,t,r)}var Ee=class{bytes=2;entries=0;truncated=!1;sink;onLimit;maxBytes;constructor(e,t,n=()=>{}){this.maxBytes=e,this.sink=t,this.onLimit=n}push(e){if(this.truncated)return;let t=+(this.entries>0),n=this.maxBytes-this.bytes-t,r=v(e,n);if(r===void 0){this.truncated=!0;let r=le(e,n);if(r.length>0){let e=v(r,n);if(e===void 0)throw new K(`worker output ledger produced an oversized log prefix`);this.bytes+=e+t,this.entries+=1,this.sink(r)}this.onLimit();return}this.bytes+=r+t,this.entries+=1,this.sink(e)}remainingOutputBytes(){return this.maxBytes-this.bytes}};const De=[`log`,`info`,`warn`,`error`,`debug`];function Oe(e){let t=e=>e.map(e=>typeof e==`string`?e:r(e,Ae)).join(` `),n=Object.create(null);for(let r of De)n[r]=(...n)=>{e.push(t(n))};return n}function ke(e,t){let n=t.write;return t.write=(t,...n)=>{e.push(typeof t==`string`?t:String(t));let r=[n[0],n[1]].find(e=>typeof e==`function`);return r&&queueMicrotask(()=>{r(null)}),!0},()=>{t.write=n}}const Ae={depth:4,maxArrayLength:100,maxStringLength:1e4};function je(e,t,n=t){if(e===void 0)return{};let r;try{r=H(e)}catch{r=void 0}return r===void 0?Ne(`invalid-output`,`program completion must be lossless JSON`,t,n):y(r,t)===void 0?Me(n):{value:U(r)}}function Me(e){return{error:{kind:`output-limit`,message:`outer output exceeded ${e} bytes`}}}function Ne(e,t,n,r){return v(t,n)===void 0?Me(r):{error:{kind:e,message:t}}}function Pe(e,t,n=t){let r;try{let t=e instanceof K?e.stack??e.message:e;r=typeof t==`string`?t:String(t)}catch{r=`program threw an unrenderable value`}return Ne(`exception`,r,t,n)}function Fe(e){return class extends K{constructor(t,n){super(n),Te(this,`name`,e.name),Te(this,e.memberNameProperty,t)}}}function q(e,t,n){return e?new e(t,n):new K(n)}function Ie(e){let t=new Map;for(let n of e.namespaces)n.errorClass&&t.set(n.global,Fe(n.errorClass));return t}function Le(e,t){e.on(`message`,e=>{let n=t.get(e.id);if(n)if(t.delete(e.id),e.ok){let t=G(e.value);t===void 0?n.reject(new K(`binding resolution must be lossless JSON`)):n.resolve(t)}else n.reject(new K(e.message))})}function Re(e,t,n,r,i=Ie(e),a){return e.namespaces.map(({global:e,names:o})=>{let s=i.get(e),c=Object.create(null);for(let i of o)Object.defineProperty(c,i,{enumerable:!0,value:o=>{let c;try{c=H(o)}catch{c=void 0}if(c===void 0)return Promise.reject(q(s,i,`binding arguments must be lossless JSON`));let l={type:`call`,id:r.value,global:e,name:i,args:U(c)};return a!==void 0&&y(l,a)===void 0?Promise.reject(q(s,i,`binding arguments exceed maxFrameBytes`)):new Promise((e,a)=>{let o=r.value++;n.set(o,{resolve:e,reject:e=>{a(q(s,i,e.message))}});try{t.postMessage(l)}catch(e){n.delete(o),a(q(s,i,`binding arguments must be structured-cloneable: ${e instanceof K?e.message:String(e)}`))}})}});return c})}async function ze(e,t,n,r){let i=new Ee(t.maxOutputBytes,t=>{e.postMessage({type:`log`,text:t})},()=>{e.postMessage({type:`output-limit`})});ke(i,n.stdout),ke(i,n.stderr);let a=new Map;Le(e,a);let o={value:1},s=Ie(t),c=Re(t,e,a,o,s,r),l=[],u=[];for(let e of t.namespaces){if(!e.errorClass)continue;l.push(e.errorClass.name);let t=s.get(e.global);if(!t)throw new K(`missing binding error class for ${e.global}`);u.push(t)}let d=Oe(i),f;try{let e=(async()=>{}).constructor;f={type:`done`,...je(await new e(...t.namespaces.map(e=>e.global),...l,`console`,`'use strict';\\n${t.code}`)(...c,...u,d),i.remainingOutputBytes(),t.maxOutputBytes)}}catch(e){f={type:`done`,...Pe(e,i.remainingOutputBytes(),t.maxOutputBytes)}}e.postMessage(r!==void 0&&y(f,r)===void 0?{type:`output-limit`}:f)}function J(e){return e.readableEnded||e.destroyed?Promise.resolve():new Promise(t=>{let n=()=>{e.off(`end`,n),e.off(`close`,n),e.off(`error`,n),t()};e.once(`end`,n),e.once(`close`,n),e.once(`error`,n),(e.readableEnded||e.destroyed)&&n()})}const Be=new Set([`exception`,`timeout`,`abort`,`worker-exit`,`invalid-output`,`output-limit`]);let Y=0;function X(e){return typeof e==`object`&&e?e:void 0}function Z(t,n){try{let r=JSON.stringify(t);return typeof r==`string`&&e.byteLength(r)<=n?r:void 0}catch{return}}function Ve(e){process.stdout.write(e),process.stdout.write(`\n`)}function He(e){let t=Z(e,Y);return t===void 0?!1:(Ve(t),!0)}function Ue(e){let t=X(e);return t!==void 0&&typeof t.kind==`string`&&Be.has(t.kind)&&typeof t.message==`string`}function We(e){return Ue(e)&&(e.kind===`exception`||e.kind===`invalid-output`||e.kind===`output-limit`)}function Ge(e,t){return e.error===void 0?{type:`done`,...e.value===void 0?{}:{value:Q(e.value)}}:t(e.error)?{type:`done`,error:e.error}:void 0}function Ke(e){let t=X(e);if(!(t===void 0||t.type!==`boot`||typeof t.code!=`string`||!Array.isArray(t.namespaces)||!Number.isSafeInteger(t.maxOutputBytes)||t.maxOutputBytes<4||!Number.isSafeInteger(t.maxFrameBytes)||t.maxFrameBytes{e.once(`exit`,()=>{t()})})}function $(){return{type:`done`,error:{kind:`worker-exit`,message:`code runtime bridge frame exceeded maxFrameBytes`}}}function Ye(){let e=n({input:process.stdin,crlfDelay:1/0}),r,a=0,o=2,s=0,c=!1,l=t=>{if(c)return;let n=Z(t,Y)??Z($(),Y);c=!0,n!==void 0&&Ve(n);let i=r;r=void 0,(i===void 0?Promise.resolve():new Promise(e=>{setImmediate(e)}).then(async()=>{let e=J(i.stdout),t=J(i.stderr),n=Je(i);i.kill(`SIGKILL`),await Promise.all([n,e,t])})).catch(e=>{process.stderr.write(`dsh-code-runtime-subprocess controller cleanup error: ${String(e)}\\n`)}).then(()=>{e.close(),process.stdin.destroy()})},u=e=>{if(c)return;let t=+(s>0),n=v(e,a-o-t);if(n===void 0){l({type:`output-limit`});return}o+=n+t,s+=1,He({type:`log`,text:e})||l($())},d=e=>{a=e.maxOutputBytes,Y=e.maxFrameBytes,r=t(i(import.meta.url),[],{env:{DSH_CODE_RUNTIME_CONTROLLER:`1`},detached:!1,execArgv:[],stdio:[`ignore`,`pipe`,`pipe`,`ipc`]});let n=r;n.stdout.on(`data`,e=>{u(e.toString(`utf8`))}),n.stderr.on(`data`,e=>{u(e.toString(`utf8`))}),n.on(`message`,e=>{let t=X(e);if(t!==void 0){if(t.type===`log`&&typeof t.text==`string`){u(t.text);return}if(!c){if(t.type===`call`&&typeof t.id==`number`&&typeof t.global==`string`&&typeof t.name==`string`)He({type:`call`,id:t.id,global:t.global,name:t.name,args:Q(t.args)})||l($());else if(t.type===`output-limit`)l({type:`output-limit`});else if(t.type===`done`){let e=Ge(t,Ue);e!==void 0&&l(e)}}}}),n.on(`error`,e=>{l({type:`done`,error:{kind:`worker-exit`,message:`remote controller error: ${e.message}`}})}),n.on(`exit`,e=>{c||l({type:`done`,error:{kind:`worker-exit`,message:`remote controller exited with code ${e} before completing`}})}),n.send(e,e=>{e!==null&&l({type:`done`,error:{kind:`worker-exit`,message:`remote controller boot failed: ${e.message}`}})})};e.on(`line`,e=>{let t;try{t=JSON.parse(e)}catch(e){process.stderr.write(`dsh-code-runtime-subprocess frame error: ${String(e)}\\n`),l({type:`done`,error:{kind:`worker-exit`,message:`remote runner received a malformed frame`}});return}if(r===void 0){let e=Ke(t);if(e===void 0){l({type:`done`,error:{kind:`worker-exit`,message:`remote runner received an invalid boot frame`}});return}d(e);return}let n=qe(t);n!==void 0&&r.send(n,e=>{e!==null&&l({type:`done`,error:{kind:`worker-exit`,message:`remote controller reply failed: ${e.message}`}})})}),e.on(`close`,()=>{r!==void 0&&!c&&l({type:`done`,error:{kind:`abort`,message:`remote runner input closed`}})})}function Xe(){let e,t=!1,n,i=0,o=e=>process.send===void 0||i>0&&Z(e,i)===void 0?!1:(process.send(e),!0),s=r=>{if(t)return;t=!0,clearInterval(n);let a=i>0&&Z(r,i)===void 0?$():r,s=e;e=void 0,(s===void 0?Promise.resolve():new Promise(e=>{setImmediate(e)}).then(async()=>{let e=J(s.stdout),t=J(s.stderr);await Promise.all([s.terminate(),e,t])})).catch(e=>{o({type:`log`,text:`dsh-code-runtime-subprocess worker cleanup error: ${String(e)}\\n`})}).then(()=>{if(process.send===void 0){process.exitCode=1;return}process.send(a,()=>{process.connected&&process.disconnect()})})};process.on(`message`,c=>{if(e===void 0){let l=Ke(c);if(l===void 0){s({type:`done`,error:{kind:`worker-exit`,message:`remote controller received an invalid boot frame`}});return}i=l.maxFrameBytes,e=new a(new URL(import.meta.url),{workerData:l,env:{},execArgv:[],stdout:!0,stderr:!0,resourceLimits:{maxOldGenerationSizeMb:l.maxOldGenerationSizeMb}});let u=e;u.stdout.on(`data`,e=>{o({type:`log`,text:e.toString(`utf8`)})||s($())}),u.stderr.on(`data`,e=>{o({type:`log`,text:e.toString(`utf8`)})||s($())}),u.on(`message`,e=>{let t=X(e);if(t!==void 0){if(t.type===`call`&&typeof t.id==`number`&&typeof t.global==`string`&&typeof t.name==`string`)o({type:`call`,id:t.id,global:t.global,name:t.name,args:Q(t.args)})||s($());else if(t.type===`log`&&typeof t.text==`string`)o({type:`log`,text:t.text})||s($());else if(t.type===`output-limit`)s({type:`output-limit`});else if(t.type===`done`){let e=Ge(t,We);e!==void 0&&s(e)}}}),u.on(`error`,e=>{s({type:`done`,error:{kind:`worker-exit`,message:`worker error: ${e.stack||e.message||r(e)}`}})}),u.on(`exit`,e=>{t||s({type:`done`,error:{kind:`worker-exit`,message:`worker exited with code ${e} before completing`}})}),n=setInterval(()=>{e!==void 0&&e.performance.eventLoopUtilization().active>l.computeMs&&s({type:`done`,error:{kind:`timeout`,message:`compute budget exhausted (${l.computeMs}ms busy)`}})},25);return}let l=qe(c);l!==void 0&&e.postMessage(l)}),process.on(`disconnect`,()=>{e!==void 0&&!t&&e.terminate()})}if(o)process.env.DSH_CODE_RUNTIME_CONTROLLER===`1`?Xe():Ye();else{if(s===null)throw Error(`remote worker requires parentPort`);let e=c;ze(s,e,{stdout:process.stdout,stderr:process.stderr},e.maxFrameBytes)}export{};" diff --git a/packages/util/atomic-write/src/runner.ts b/packages/util/atomic-write/src/runner.ts index 7a0b3eb678..92fad6db2e 100644 --- a/packages/util/atomic-write/src/runner.ts +++ b/packages/util/atomic-write/src/runner.ts @@ -94,6 +94,16 @@ function validWorkerFailure(value: unknown): value is RuntimeFailure { && (value.kind === 'exception' || value.kind === 'invalid-output' || value.kind === 'output-limit') } +function doneMessage( + message: Record, + acceptsFailure: (value: unknown) => value is RuntimeFailure, +): RuntimeMessage | undefined { + if (message.error !== undefined) { + return acceptsFailure(message.error) ? { type: 'done', error: message.error } : undefined + } + return { type: 'done', ...message.value === undefined ? {} : { value: transportWireOrNull(message.value) } } +} + function runtimeBoot(value: unknown): RuntimeBootData | undefined { const record = recordOf(value) if (record === undefined @@ -214,11 +224,8 @@ function runLauncher(): void { } else if (message.type === 'output-limit') { finish({ type: 'output-limit' }) } else if (message.type === 'done') { - if (message.error !== undefined) { - if (validFailure(message.error)) finish({ type: 'done', error: message.error }) - } else { - finish({ type: 'done', ...message.value === undefined ? {} : { value: transportWireOrNull(message.value) } }) - } + const done = doneMessage(message, validFailure) + if (done !== undefined) finish(done) } }) current.on('error', (error: Error) => { @@ -348,11 +355,8 @@ function runController(): void { } else if (message.type === 'output-limit') { finish({ type: 'output-limit' }) } else if (message.type === 'done') { - if (message.error !== undefined) { - if (validWorkerFailure(message.error)) finish({ type: 'done', error: message.error }) - } else { - finish({ type: 'done', ...message.value === undefined ? {} : { value: transportWireOrNull(message.value) } }) - } + const done = doneMessage(message, validWorkerFailure) + if (done !== undefined) finish(done) } }) current.on('error', (error: Error) => {