@econ-v1/app-sdk 7.6.10 → 7.6.12

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 CHANGED
@@ -67,13 +67,19 @@ worker-thread detection. Differences an app can observe:
67
67
  - Telemetry stays inactive (`telemetryActive()` is `false`): Burger Phase 1
68
68
  has no `fetch` for an OTLP exporter.
69
69
  - `heap_snapshot_request` is answered with `success: false`.
70
- - A nested `invokeCapability` carries `invocation_context_id` only when it
71
- is made before the handler's first `await` (Burger Phase 1 has no
72
- `AsyncLocalStorage`); later calls are classified by the host as background
73
- work, never as foreground. This is the known Phase 1 limitation recorded
74
- in Burger Contract C6
75
- (`docs/superpowers/plans/2026-09-17-burger-00-overview-and-contracts.md`)
76
- and fixed by `burger-08`.
70
+ - On node-app-burger >= 0.3.3 a nested `invokeCapability` carries
71
+ `invocation_context_id` however many `await`s separate it from the
72
+ handler, as on Bun: the SDK loads `burger:async_hooks` (ADR 004) with a
73
+ dynamic import and uses its `AsyncLocalStorage`. On an older runtime that
74
+ import fails quietly and the Phase 1 behaviour stays: only calls made
75
+ before the handler's first `await` carry the id, later ones are classified
76
+ by the host as background work, never as foreground (Burger Contract C6,
77
+ `docs/superpowers/plans/2026-09-17-burger-00-overview-and-contracts.md`).
78
+ The same SDK therefore loads on every runtime version. Rebuilding an app on
79
+ this SDK changes its nested calls on 0.3.3: they now carry the caller's
80
+ context, so the host judges them under that caller (and rejects them with
81
+ `capability.invalid_invocation_context` if the caller's context has already
82
+ closed). Run the app's suite on 0.3.3 before releasing it.
77
83
 
78
84
  Burger apps bundle the SDK into `dist/index.js`; nothing is shared at runtime.
79
85
 
@@ -1,2 +1,2 @@
1
- var ue=Object.defineProperty;var le=(e)=>e;function de(e,t){this[e]=le.bind(null,t)}var fe=(e,t)=>{for(var r in t)ue(e,r,{get:t[r],enumerable:!0,configurable:!0,set:de.bind(t,r)})};import{Database as Se}from"burger:sqlite";var N={};fe(N,{incrementCounter:()=>q,initAppTelemetry:()=>T,injectTraceContext:()=>me,telemetryActive:()=>L,traceIncomingCapability:()=>ye});async function T(e){}function L(){return!1}function q(e,t=1,r){}function me(e){return e}async function ye(e,t,r){return r()}import{connect as ge,dataDir as be,exit as G,logDir as _e,memoryUsage as he}from"burger:host";var H=!0,Y=256;function F(){return{socket:void 0,logDir:_e,dataDir:be}}var B=F();function Q(){return B.socket}function V(e,t,r=G){r(e)}function b(e){G(e)}function Z(){}var ve=/the app channel is (not open|closed)/;function X(e){let t=ge(),r=!0,n=!1;function i(o){if(n)return;try{t.send(o)}catch(a){if(a instanceof Error&&ve.test(a.message)){n=!0;return}throw a}}return t.onFrame((o)=>{if(!r)return;e.onFrame(o).catch((a)=>e.onFrameError(a))}),t.onClose((o)=>{if(n=!0,o)e.onError(o);else e.onClose()}),queueMicrotask(()=>e.onConnected("burger:host")),{send(o){i(o)},sendAndFlush(o){return i(o),Promise.resolve()},stopAccepting(){r=!1},end(){n=!0,t.close()}}}function J(){let e;return{run(t,r){let n=e;e=t;try{return r()}finally{e=n}},getStore(){return e}}}function ee(){let e=he();return{heap_used_kb:Math.round(e.heap_used_kb),heap_total_kb:Math.round(e.heap_total_kb),external_kb:Math.round(e.external_kb),heap_capacity_kb:Math.round(e.heap_capacity_kb)}}function K(){throw Error("heap snapshots are not available in the Burger runtime")}async function te(e,t=K,r=K){let n=t();return{size_bytes:await r(e,n)}}import*as s from"burger:fs";import{join as Re}from"burger:path";var Ce=60000,Ie=52428800,Ae=10485760;function ne(e,t={}){if(!e)return{write:()=>{}};let r=Re(e,"app.log"),n=t.reportError??((l)=>console.error(l)),i=t.now??Date.now,o=t.maxBytes??Ie,a=Math.min(t.tailBytes??Ae,o),p=typeof s.openSync==="function"&&typeof s.writeSync==="function"&&typeof s.closeSync==="function"&&typeof s.fstatSync==="function"&&typeof s.readSync==="function"&&typeof s.ftruncateSync==="function",c=null,O=!1,M=null,R=0;function W(){if(O)return;s.mkdirSync(e,{recursive:!0}),O=!0}function ce(l){let C=i();if(M!==null&&C-M<Ce){R+=1;return}let I=l instanceof Error?l.message:String(l),d=R>0?`; ${R} earlier failure(s) not reported`:"";n(`[node-app-sdk] app.log write failed (${r}): ${I}${d}`),M=C,R=0}return{write(l,C){let I=`${new Date().toISOString()} [${l.toUpperCase().padEnd(5)}] ${C}
2
- `;try{if(!p){W(),s.appendFileSync(r,I);return}if(c===null)W(),c=s.openSync(r,"a+");let d=s.fstatSync(c).size;if(d>o){let P=Math.min(d,a),U=Buffer.alloc(P);s.readSync(c,U,0,P,d-P),s.ftruncateSync(c,0),s.writeSync(c,U)}s.writeSync(c,I)}catch(d){if(c!==null){try{s.closeSync(c)}catch{}c=null}ce(d)}}}}var{injectTraceContext:we,traceIncomingCapability:Ee}=N,ke=T,Ye=L,Qe=q,Me=Y;function Ve(e,t={}){let r=t.cacheSizeKb??Me;if(!Number.isInteger(r)||r<=0)throw RangeError("cacheSizeKb must be a positive integer");let n=new Se(e);try{return n.exec(`PRAGMA cache_size = -${r}`),n}catch(i){throw n.close(),i}}var Ze=F,Xe=Q,Je=V,Pe=ne(B.logDir),u=null,ie=J(),h=new Map,f={trace:(e)=>_("trace",e),debug:(e)=>_("debug",e),info:(e)=>_("info",e),warn:(e)=>_("warn",e),error:(e)=>_("error",e),holdLease:()=>{let e=!1;return A(),()=>{if(e)return;e=!0,S()}}};function _(e,t){if(Pe.write(e,t),u)u({type:"log",level:e,message:t});else console[e==="trace"?"debug":e](t)}function et(e,t){if(!u)return Promise.reject(Error("Not connected to host"));let r=t??30000,n=e.timeout_ms===void 0?{...e,timeout_ms:r}:e,i={...n,trace_context:we({...n.trace_context??{}})},o=ie.getStore();if(o?.active&&o.id!==void 0)i.invocation_context_id=o.id;return new Promise((a,p)=>{h.set(e.id,{resolve:a,reject:p}),u({type:"invoke_capability",id:e.id,request:i}),setTimeout(()=>{if(h.has(e.id))h.delete(e.id),p(Error(`Capability invocation timed out after ${r}ms: ${e.capability}`))},r)})}function tt(e,t){if(!u)throw Error("Not connected to host");u({type:"publish_event",event_name:e,data:t})}var m=0,v,y=null,x=!1,E,se=()=>b(0),z=se,D,ae=(e)=>(u?.(e),Promise.resolve()),j=ae;function re(e){if(v=e,e===void 0)k()}function k(){if(y)clearTimeout(y),y=null}function Te(){if(x)return;if(v===void 0)return;if(m!==0)return;k();let e=Math.max(0,v*1000),t=setTimeout(()=>{y=null,Le()},e);t.unref?.(),y=t}function A(){m++,k()}function S(){if(m=Math.max(0,m-1),m===0)Te()}async function Le(){if(x)return;if(x=!0,D?.(),E)await E.shutdown();await j({type:"lease_exit"}),z()}function nt(){k(),m=0,v=void 0,x=!1,E=void 0,z=se,D=void 0,j=ae}function rt(e){z=e}function ot(){return{inFlight:m,rememberedSecs:v,timerArmed:y!==null,draining:x}}var qe=30000;function Ne(){let e=process.env.NODE_APP_MEMORY_SAMPLE_INTERVAL_MS,t=e?Number.parseInt(e,10):NaN;return Number.isFinite(t)&&t>=1000?t:qe}var g=null,He=ee;function oe(e){e({type:"app_memory",...He()})}function Fe(e){if(g)return;oe(e),g=setInterval(()=>oe(e),Ne()),g.unref?.()}function w(){if(g)clearInterval(g),g=null}var $e=te;async function Be(e,t,r=$e){try{let n=await r(e.path);t({type:"heap_snapshot_response",id:e.id,success:!0,size_bytes:n.size_bytes})}catch{t({type:"heap_snapshot_response",id:e.id,success:!1,error:"heap_snapshot_failed"})}}function ze(e,t){let r=t.indexOf("?"),n=r>=0?t.slice(0,r):t,i=e.split("/"),o=n.split("/"),a=0,p=0;while(a<i.length){if(i[a]==="**")return!0;if(p>=o.length)return!1;if(i[a]!=="*"&&i[a]!==o[p])return!1;a++,p++}return p===o.length}class De{_routes=[];route(e,t,r,n){this._routes.push({method:e,path:t,policy:r,handler:n})}async init(e){}async shutdown(){}async handleRequest(e){if(this._routes.length>0)return this._dispatchRoute(e);return{status:501,headers:{},body:{error:"Not implemented"}}}async _dispatchRoute(e){let t=e.method.toUpperCase(),r=e.path;for(let n of this._routes){if(!(n.method==="*"||n.method.toUpperCase()===t))continue;if(!ze(n.path,r))continue;let o=n.policy.requiredPermissions??[],a=e.caller?.granted_permissions??[],p=o.filter((c)=>!a.includes(c));if(p.length>0)return f.warn(`SDK scope denied: [${p.join(", ")}] missing for ${t} ${r}`),{status:403,headers:{},body:{error:`Missing permissions: ${p.join(", ")}`}};return n.handler(e)}return this.notFound()}async handleEvent(e){}providedCapabilities(){return[]}async handleCapability(e){return{id:e.id,success:!1,payload:{error:"Capability handling not implemented"}}}json(e,t=200){return{status:t,headers:{"Content-Type":"application/json"},body:e}}error(e,t=500){return{status:t,headers:{"Content-Type":"application/json"},body:{error:e}}}notFound(){return this.error("Not found",404)}}function it(e){Z(),ke(e.metadata?.name??"node-app");let t=X({onConnected:(n)=>{f.debug(`Connected to host via ${n}`)},onFrame:(n)=>pe(e,n,r),onFrameError:(n)=>{f.error(`Failed to parse IPC message: ${n}`)},onError:(n)=>{console.error(`[node-app-sdk] Socket error: ${n.message}`),b(1)},onClose:()=>{w(),b(0),f.debug("Socket closed, shutting down")}});function r(n){t.send(n)}u=r,D=()=>{t.stopAccepting()},j=(n)=>t.sendAndFlush(n),process.on("SIGTERM",async()=>{if(!H)return;w(),await e.shutdown(),t.end(),process.exit(0)}),process.on("SIGINT",async()=>{if(!H)return;w(),await e.shutdown(),t.end(),process.exit(0)})}async function pe(e,t,r){switch(E=e,t.type){case"init":{let n=t.config;await e.init(n),r({type:"ready",metadata:e.metadata}),Fe(r);break}case"request":{let{id:n,request:i}=t;A();try{let o=await e.handleRequest(i);r({type:"response",id:n,response:o})}catch(o){r({type:"response",id:n,response:{status:500,headers:{},body:{error:`Internal app error: ${o}`}}})}finally{S()}break}case"event":{let{event:n,lease_secs:i}=t;re(i),A();try{await e.handleEvent(n)}catch(o){f.error(`Event handler error: ${o}`)}finally{S()}break}case"capability_request":{let{id:n,request:i}=t;re(i.lease_secs),A();let o={id:i.invocation_context_id,active:!0};try{let a=await ie.run(o,async()=>{try{return await Ee(i.capability,i.trace_context,()=>e.handleCapability(i))}finally{o.active=!1}});r({type:"capability_response",id:n,response:a})}catch(a){r({type:"capability_response",id:n,response:{id:i.id,success:!1,payload:{error:`Capability handler error: ${a}`}}})}finally{S()}break}case"invoke_capability_result":{let{id:n,response:i}=t,o=h.get(n);if(o)h.delete(n),o.resolve(i);break}case"shutdown":{f.info("Received shutdown signal from host"),w(),await e.shutdown(),b(0);break}case"heap_snapshot_request":{await Be(t,r);break}default:f.warn(`Unknown IPC message type: ${t.type}`)}}async function st(e,t,r){u=r,await pe(e,t,u)}export{De as NodeApp,$e as _captureHeapSnapshotTo,Be as _handleHeapSnapshotRequest,Ze as _resolveCtx,He as _sampleMemory,Je as _testExitWorker,st as _testHandleMessage,ot as _testLeaseState,nt as _testResetLeaseState,Xe as _testRunNodeAppPath,rt as _testSetLeaseExitFn,f as host,Qe as incrementCounter,ke as initAppTelemetry,et as invokeCapability,Ve as openDatabase,tt as publishEvent,it as runNodeApp,Ye as telemetryActive};
1
+ var fe=Object.defineProperty;var me=(e)=>e;function ye(e,t){this[e]=me.bind(null,t)}var ge=(e,t)=>{for(var o in t)fe(e,o,{get:t[o],enumerable:!0,configurable:!0,set:ye.bind(t,o)})};import{Database as ke}from"burger:sqlite";var N={};ge(N,{incrementCounter:()=>q,initAppTelemetry:()=>P,injectTraceContext:()=>be,telemetryActive:()=>L,traceIncomingCapability:()=>_e});async function P(e){}function L(){return!1}function q(e,t=1,o){}function be(e){return e}async function _e(e,t,o){return o()}import{connect as ve,dataDir as xe,exit as V,logDir as Ce,memoryUsage as Ie}from"burger:host";var K=null,Ge=import("burger:async_hooks").then((e)=>(K=e.AsyncLocalStorage,!0),()=>!1);function G(){return K}function Y(e){let t=he(),o=null,n=()=>{if(o)return o;let i=e();if(!i)return t;return o=new i,o};return{run(i,r){return n().run(i,r)},getStore(){return n().getStore()}}}function he(){let e;return{run(t,o){let n=e;e=t;try{return o()}finally{e=n}},getStore(){return e}}}var H=!0,Z=256;function F(){return{socket:void 0,logDir:Ce,dataDir:xe}}var B=F();function X(){return B.socket}function J(e,t,o=V){o(e)}function b(e){V(e)}function ee(){}var Se=/the app channel is (not open|closed)/;function te(e){let t=ve(),o=!0,n=!1;function i(r){if(n)return;try{t.send(r)}catch(a){if(a instanceof Error&&Se.test(a.message)){n=!0;return}throw a}}return t.onFrame((r)=>{if(!o)return;e.onFrame(r).catch((a)=>e.onFrameError(a))}),t.onClose((r)=>{if(n=!0,r)e.onError(r);else e.onClose()}),queueMicrotask(()=>e.onConnected("burger:host")),{send(r){i(r)},sendAndFlush(r){return i(r),Promise.resolve()},stopAccepting(){o=!1},end(){n=!0,t.close()}}}function ne(){return Y(G)}function oe(){let e=Ie();return{heap_used_kb:Math.round(e.heap_used_kb),heap_total_kb:Math.round(e.heap_total_kb),external_kb:Math.round(e.external_kb),heap_capacity_kb:Math.round(e.heap_capacity_kb)}}function Q(){throw Error("heap snapshots are not available in the Burger runtime")}async function re(e,t=Q,o=Q){let n=t();return{size_bytes:await o(e,n)}}import*as s from"burger:fs";import{join as Ae}from"burger:path";var we=60000,Ee=52428800,Te=10485760;function ie(e,t={}){if(!e)return{write:()=>{}};let o=Ae(e,"app.log"),n=t.reportError??((l)=>console.error(l)),i=t.now??Date.now,r=t.maxBytes??Ee,a=Math.min(t.tailBytes??Te,r),p=typeof s.openSync==="function"&&typeof s.writeSync==="function"&&typeof s.closeSync==="function"&&typeof s.fstatSync==="function"&&typeof s.readSync==="function"&&typeof s.ftruncateSync==="function",c=null,O=!1,k=null,C=0;function W(){if(O)return;s.mkdirSync(e,{recursive:!0}),O=!0}function de(l){let I=i();if(k!==null&&I-k<we){C+=1;return}let S=l instanceof Error?l.message:String(l),d=C>0?`; ${C} earlier failure(s) not reported`:"";n(`[node-app-sdk] app.log write failed (${o}): ${S}${d}`),k=I,C=0}return{write(l,I){let S=`${new Date().toISOString()} [${l.toUpperCase().padEnd(5)}] ${I}
2
+ `;try{if(!p){W(),s.appendFileSync(o,S);return}if(c===null)W(),c=s.openSync(o,"a+");let d=s.fstatSync(c).size;if(d>r){let M=Math.min(d,a),U=Buffer.alloc(M);s.readSync(c,U,0,M,d-M),s.ftruncateSync(c,0),s.writeSync(c,U)}s.writeSync(c,S)}catch(d){if(c!==null){try{s.closeSync(c)}catch{}c=null}de(d)}}}}var{injectTraceContext:Me,traceIncomingCapability:Pe}=N,Le=P,tt=L,nt=q,qe=Z;function ot(e,t={}){let o=t.cacheSizeKb??qe;if(!Number.isInteger(o)||o<=0)throw RangeError("cacheSizeKb must be a positive integer");let n=new ke(e);try{return n.exec(`PRAGMA cache_size = -${o}`),n}catch(i){throw n.close(),i}}var rt=F,it=X,st=J,Ne=ie(B.logDir),u=null,pe=ne(),h=new Map,f={trace:(e)=>_("trace",e),debug:(e)=>_("debug",e),info:(e)=>_("info",e),warn:(e)=>_("warn",e),error:(e)=>_("error",e),holdLease:()=>{let e=!1;return R(),()=>{if(e)return;e=!0,A()}}};function _(e,t){if(Ne.write(e,t),u)u({type:"log",level:e,message:t});else console[e==="trace"?"debug":e](t)}function at(e,t){if(!u)return Promise.reject(Error("Not connected to host"));let o=t??30000,n=e.timeout_ms===void 0?{...e,timeout_ms:o}:e,i={...n,trace_context:Me({...n.trace_context??{}})},r=pe.getStore();if(r?.active&&r.id!==void 0)i.invocation_context_id=r.id;return new Promise((a,p)=>{h.set(e.id,{resolve:a,reject:p}),u({type:"invoke_capability",id:e.id,request:i}),setTimeout(()=>{if(h.has(e.id))h.delete(e.id),p(Error(`Capability invocation timed out after ${o}ms: ${e.capability}`))},o)})}function pt(e,t){if(!u)throw Error("Not connected to host");u({type:"publish_event",event_name:e,data:t})}var m=0,v,y=null,x=!1,E,ce=()=>b(0),j=ce,z,ue=(e)=>(u?.(e),Promise.resolve()),D=ue;function se(e){if(v=e,e===void 0)T()}function T(){if(y)clearTimeout(y),y=null}function He(){if(x)return;if(v===void 0)return;if(m!==0)return;T();let e=Math.max(0,v*1000),t=setTimeout(()=>{y=null,Fe()},e);t.unref?.(),y=t}function R(){m++,T()}function A(){if(m=Math.max(0,m-1),m===0)He()}async function Fe(){if(x)return;if(x=!0,z?.(),E)await E.shutdown();await D({type:"lease_exit"}),j()}function ct(){T(),m=0,v=void 0,x=!1,E=void 0,j=ce,z=void 0,D=ue}function ut(e){j=e}function lt(){return{inFlight:m,rememberedSecs:v,timerArmed:y!==null,draining:x}}var $e=30000;function Be(){let e=process.env.NODE_APP_MEMORY_SAMPLE_INTERVAL_MS,t=e?Number.parseInt(e,10):NaN;return Number.isFinite(t)&&t>=1000?t:$e}var g=null,je=oe;function ae(e){e({type:"app_memory",...je()})}function ze(e){if(g)return;ae(e),g=setInterval(()=>ae(e),Be()),g.unref?.()}function w(){if(g)clearInterval(g),g=null}var De=re;async function Oe(e,t,o=De){try{let n=await o(e.path);t({type:"heap_snapshot_response",id:e.id,success:!0,size_bytes:n.size_bytes})}catch{t({type:"heap_snapshot_response",id:e.id,success:!1,error:"heap_snapshot_failed"})}}function We(e,t){let o=t.indexOf("?"),n=o>=0?t.slice(0,o):t,i=e.split("/"),r=n.split("/"),a=0,p=0;while(a<i.length){if(i[a]==="**")return!0;if(p>=r.length)return!1;if(i[a]!=="*"&&i[a]!==r[p])return!1;a++,p++}return p===r.length}class Ue{_routes=[];route(e,t,o,n){this._routes.push({method:e,path:t,policy:o,handler:n})}async init(e){}async shutdown(){}async handleRequest(e){if(this._routes.length>0)return this._dispatchRoute(e);return{status:501,headers:{},body:{error:"Not implemented"}}}async _dispatchRoute(e){let t=e.method.toUpperCase(),o=e.path;for(let n of this._routes){if(!(n.method==="*"||n.method.toUpperCase()===t))continue;if(!We(n.path,o))continue;let r=n.policy.requiredPermissions??[],a=e.caller?.granted_permissions??[],p=r.filter((c)=>!a.includes(c));if(p.length>0)return f.warn(`SDK scope denied: [${p.join(", ")}] missing for ${t} ${o}`),{status:403,headers:{},body:{error:`Missing permissions: ${p.join(", ")}`}};return n.handler(e)}return this.notFound()}async handleEvent(e){}providedCapabilities(){return[]}async handleCapability(e){return{id:e.id,success:!1,payload:{error:"Capability handling not implemented"}}}json(e,t=200){return{status:t,headers:{"Content-Type":"application/json"},body:e}}error(e,t=500){return{status:t,headers:{"Content-Type":"application/json"},body:{error:e}}}notFound(){return this.error("Not found",404)}}function dt(e){ee(),Le(e.metadata?.name??"node-app");let t=te({onConnected:(n)=>{f.debug(`Connected to host via ${n}`)},onFrame:(n)=>le(e,n,o),onFrameError:(n)=>{f.error(`Failed to parse IPC message: ${n}`)},onError:(n)=>{console.error(`[node-app-sdk] Socket error: ${n.message}`),b(1)},onClose:()=>{w(),b(0),f.debug("Socket closed, shutting down")}});function o(n){t.send(n)}u=o,z=()=>{t.stopAccepting()},D=(n)=>t.sendAndFlush(n),process.on("SIGTERM",async()=>{if(!H)return;w(),await e.shutdown(),t.end(),process.exit(0)}),process.on("SIGINT",async()=>{if(!H)return;w(),await e.shutdown(),t.end(),process.exit(0)})}async function le(e,t,o){switch(E=e,t.type){case"init":{let n=t.config;await e.init(n),o({type:"ready",metadata:e.metadata}),ze(o);break}case"request":{let{id:n,request:i}=t;R();try{let r=await e.handleRequest(i);o({type:"response",id:n,response:r})}catch(r){o({type:"response",id:n,response:{status:500,headers:{},body:{error:`Internal app error: ${r}`}}})}finally{A()}break}case"event":{let{event:n,lease_secs:i}=t;se(i),R();try{await e.handleEvent(n)}catch(r){f.error(`Event handler error: ${r}`)}finally{A()}break}case"capability_request":{let{id:n,request:i}=t;se(i.lease_secs),R();let r={id:i.invocation_context_id,active:!0};try{let a=await pe.run(r,async()=>{try{return await Pe(i.capability,i.trace_context,()=>e.handleCapability(i))}finally{r.active=!1}});o({type:"capability_response",id:n,response:a})}catch(a){o({type:"capability_response",id:n,response:{id:i.id,success:!1,payload:{error:`Capability handler error: ${a}`}}})}finally{A()}break}case"invoke_capability_result":{let{id:n,response:i}=t,r=h.get(n);if(r)h.delete(n),r.resolve(i);break}case"shutdown":{f.info("Received shutdown signal from host"),w(),await e.shutdown(),b(0);break}case"heap_snapshot_request":{await Oe(t,o);break}default:f.warn(`Unknown IPC message type: ${t.type}`)}}async function ft(e,t,o){u=o,await le(e,t,u)}export{Ue as NodeApp,De as _captureHeapSnapshotTo,Oe as _handleHeapSnapshotRequest,rt as _resolveCtx,je as _sampleMemory,st as _testExitWorker,ft as _testHandleMessage,lt as _testLeaseState,ct as _testResetLeaseState,it as _testRunNodeAppPath,ut as _testSetLeaseExitFn,f as host,nt as incrementCounter,Le as initAppTelemetry,at as invokeCapability,ot as openDatabase,pt as publishEvent,dt as runNodeApp,tt as telemetryActive};
@@ -3,7 +3,7 @@
3
3
  * they become. Everything here is data; `classifySpecifier` is the only
4
4
  * decision function.
5
5
  */
6
- export declare const BURGER_MODULES: readonly ["burger:host", "burger:fs", "burger:fs/promises", "burger:path", "burger:os", "burger:worker_threads", "burger:crypto", "burger:buffer", "burger:sqlite", "burger:test"];
6
+ export declare const BURGER_MODULES: readonly ["burger:host", "burger:fs", "burger:fs/promises", "burger:path", "burger:os", "burger:worker_threads", "burger:crypto", "burger:buffer", "burger:sqlite", "burger:zlib", "burger:async_hooks", "burger:test"];
7
7
  export type BurgerModule = (typeof BURGER_MODULES)[number];
8
8
  /** C5/C6 "Aliased from" columns (plus `fs/promises`, the module form of `fs.promises`). */
9
9
  export declare const ALIASES: ReadonlyMap<string, BurgerModule>;
@@ -18,6 +18,13 @@ export declare const NODE_BUILTINS: ReadonlySet<string>;
18
18
  * Named exports of each `burger:*` module (C4, C6). Used to bridge CommonJS
19
19
  * `require()`.
20
20
  *
21
+ * AGENT RUNTIME PACK (node-app-burger >= 0.3.3): `burger:zlib` and
22
+ * `burger:async_hooks` provide only the names listed below. The gate checks
23
+ * named ESM imports against them, but a CommonJS `require("zlib")` or
24
+ * `require("async_hooks")` cannot be checked: a package that also reaches for
25
+ * `inflateSync`, streams, `AsyncResource` or `createHook` builds and then reads
26
+ * `undefined` at run time.
27
+ *
21
28
  * DATA-APP PACK: `realpathSync`, `copyFileSync`, `symlinkSync`, `openSync`,
22
29
  * `writeSync`, `fsyncSync`, `fdatasyncSync`, `closeSync`, `Dirent` and
23
30
  * `constants` on `burger:fs` ship with the data-app pack
@@ -32,6 +32,8 @@ var BURGER_MODULES = [
32
32
  "burger:crypto",
33
33
  "burger:buffer",
34
34
  "burger:sqlite",
35
+ "burger:zlib",
36
+ "burger:async_hooks",
35
37
  "burger:test"
36
38
  ];
37
39
  var ALIASES = new Map([
@@ -50,6 +52,10 @@ var ALIASES = new Map([
50
52
  ["node:buffer", "burger:buffer"],
51
53
  ["buffer", "burger:buffer"],
52
54
  ["bun:sqlite", "burger:sqlite"],
55
+ ["node:zlib", "burger:zlib"],
56
+ ["zlib", "burger:zlib"],
57
+ ["node:async_hooks", "burger:async_hooks"],
58
+ ["async_hooks", "burger:async_hooks"],
53
59
  ["bun:test", "burger:test"]
54
60
  ]);
55
61
  var NODE_BUILTINS = new Set([
@@ -185,6 +191,8 @@ var BURGER_EXPORTS = {
185
191
  "burger:crypto": ["randomUUID", "randomBytes", "createHash", "createHmac", "timingSafeEqual"],
186
192
  "burger:buffer": ["Buffer"],
187
193
  "burger:sqlite": ["Database"],
194
+ "burger:zlib": ["gzipSync", "gunzipSync", "constants"],
195
+ "burger:async_hooks": ["AsyncLocalStorage"],
188
196
  "burger:test": [
189
197
  "describe",
190
198
  "test",
@@ -206,7 +214,9 @@ var BURGER_DEFAULT_EXPORT = {
206
214
  "burger:worker_threads": true,
207
215
  "burger:crypto": true,
208
216
  "burger:buffer": true,
209
- "burger:sqlite": true
217
+ "burger:sqlite": true,
218
+ "burger:zlib": true,
219
+ "burger:async_hooks": true
210
220
  };
211
221
  var BURGER_MODULE_SET = new Set(BURGER_MODULES);
212
222
  function classifySpecifier(specifier) {
@@ -785,6 +795,15 @@ ${named}`);
785
795
  return { problems };
786
796
  return { code: await result.outputs[0].text() };
787
797
  }
798
+ function bunfigTestPreloads(projectDir) {
799
+ const path = join2(projectDir, "bunfig.toml");
800
+ if (!existsSync(path))
801
+ return [];
802
+ const config = Bun.TOML.parse(readFileSync2(path, "utf8"));
803
+ const preload = config.test?.preload;
804
+ const entries = typeof preload === "string" ? [preload] : Array.isArray(preload) ? preload : [];
805
+ return entries.filter((entry) => typeof entry === "string").map((entry) => resolveRelativeFile(projectDir, entry)).filter((file) => file !== undefined);
806
+ }
788
807
  async function prepareTests(options) {
789
808
  assertSupportedBun();
790
809
  const cwd = process.cwd();
@@ -842,6 +861,7 @@ async function prepareTests(options) {
842
861
  `) };
843
862
  }
844
863
  }
864
+ const preloads = bunfigTestPreloads(cwd).filter((file) => ws.sources.has(file));
845
865
  for (const file of files) {
846
866
  const output = join2(out, preparedPath(relative2(root, file)));
847
867
  const prepared = readFileSync2(output, "utf8").replace(MOCK_MODULE_CALL, (call, quote, specifier) => {
@@ -849,7 +869,9 @@ async function prepareTests(options) {
849
869
  const replacement = rewritten === undefined ? undefined : ("external" in rewritten) ? rewritten.external : undefined;
850
870
  return replacement === undefined ? call : call.replace(`${quote}${specifier}${quote}`, JSON.stringify(replacement));
851
871
  });
852
- writeFileSync2(output, prepared);
872
+ const preloadImports = TEST_FILE.test(file) ? preloads.map((preload) => `import ${JSON.stringify(relativeSpecifier(dirname(output), join2(out, preparedPath(relative2(root, preload)))))};
873
+ `).join("") : "";
874
+ writeFileSync2(output, preloadImports + prepared);
853
875
  const source = readFileSync2(file, "utf8");
854
876
  const code = codeOf(file, source) ?? source;
855
877
  const imports = new Bun.Transpiler({ loader: loaderFor2(file) }).scan(source).imports;
@@ -27,6 +27,8 @@ var BURGER_MODULES = [
27
27
  "burger:crypto",
28
28
  "burger:buffer",
29
29
  "burger:sqlite",
30
+ "burger:zlib",
31
+ "burger:async_hooks",
30
32
  "burger:test"
31
33
  ];
32
34
  var ALIASES = new Map([
@@ -45,6 +47,10 @@ var ALIASES = new Map([
45
47
  ["node:buffer", "burger:buffer"],
46
48
  ["buffer", "burger:buffer"],
47
49
  ["bun:sqlite", "burger:sqlite"],
50
+ ["node:zlib", "burger:zlib"],
51
+ ["zlib", "burger:zlib"],
52
+ ["node:async_hooks", "burger:async_hooks"],
53
+ ["async_hooks", "burger:async_hooks"],
48
54
  ["bun:test", "burger:test"]
49
55
  ]);
50
56
  var NODE_BUILTINS = new Set([
@@ -180,6 +186,8 @@ var BURGER_EXPORTS = {
180
186
  "burger:crypto": ["randomUUID", "randomBytes", "createHash", "createHmac", "timingSafeEqual"],
181
187
  "burger:buffer": ["Buffer"],
182
188
  "burger:sqlite": ["Database"],
189
+ "burger:zlib": ["gzipSync", "gunzipSync", "constants"],
190
+ "burger:async_hooks": ["AsyncLocalStorage"],
183
191
  "burger:test": [
184
192
  "describe",
185
193
  "test",
@@ -201,7 +209,9 @@ var BURGER_DEFAULT_EXPORT = {
201
209
  "burger:worker_threads": true,
202
210
  "burger:crypto": true,
203
211
  "burger:buffer": true,
204
- "burger:sqlite": true
212
+ "burger:sqlite": true,
213
+ "burger:zlib": true,
214
+ "burger:async_hooks": true
205
215
  };
206
216
  var BURGER_MODULE_SET = new Set(BURGER_MODULES);
207
217
  function classifySpecifier(specifier) {
@@ -779,6 +789,15 @@ ${named}`);
779
789
  return { problems };
780
790
  return { code: await result.outputs[0].text() };
781
791
  }
792
+ function bunfigTestPreloads(projectDir) {
793
+ const path = join2(projectDir, "bunfig.toml");
794
+ if (!existsSync(path))
795
+ return [];
796
+ const config = Bun.TOML.parse(readFileSync2(path, "utf8"));
797
+ const preload = config.test?.preload;
798
+ const entries = typeof preload === "string" ? [preload] : Array.isArray(preload) ? preload : [];
799
+ return entries.filter((entry) => typeof entry === "string").map((entry) => resolveRelativeFile(projectDir, entry)).filter((file) => file !== undefined);
800
+ }
782
801
  async function prepareTests(options) {
783
802
  assertSupportedBun();
784
803
  const cwd = process.cwd();
@@ -836,6 +855,7 @@ async function prepareTests(options) {
836
855
  `) };
837
856
  }
838
857
  }
858
+ const preloads = bunfigTestPreloads(cwd).filter((file) => ws.sources.has(file));
839
859
  for (const file of files) {
840
860
  const output = join2(out, preparedPath(relative2(root, file)));
841
861
  const prepared = readFileSync2(output, "utf8").replace(MOCK_MODULE_CALL, (call, quote, specifier) => {
@@ -843,7 +863,9 @@ async function prepareTests(options) {
843
863
  const replacement = rewritten === undefined ? undefined : ("external" in rewritten) ? rewritten.external : undefined;
844
864
  return replacement === undefined ? call : call.replace(`${quote}${specifier}${quote}`, JSON.stringify(replacement));
845
865
  });
846
- writeFileSync2(output, prepared);
866
+ const preloadImports = TEST_FILE.test(file) ? preloads.map((preload) => `import ${JSON.stringify(relativeSpecifier(dirname(output), join2(out, preparedPath(relative2(root, preload)))))};
867
+ `).join("") : "";
868
+ writeFileSync2(output, preloadImports + prepared);
847
869
  const source = readFileSync2(file, "utf8");
848
870
  const code = codeOf(file, source) ?? source;
849
871
  const imports = new Bun.Transpiler({ loader: loaderFor2(file) }).scan(source).imports;
@@ -65,6 +65,11 @@ export declare function staticallyImportedMocks(file: string, code: string, impo
65
65
  kind: string;
66
66
  path: string;
67
67
  }[]): string[];
68
+ /**
69
+ * The files `bunfig.toml` `[test] preload` names in `projectDir`, resolved like
70
+ * a relative import. `bun test` evaluates them before each test file.
71
+ */
72
+ export declare function bunfigTestPreloads(projectDir: string): string[];
68
73
  /**
69
74
  * Turn an app's sources and tests into files `node-app-burger test` can run:
70
75
  * one transpiled ES module per source file (module boundaries preserved so
@@ -17,4 +17,10 @@ declare module "crypto" { export * from "burger:crypto"; export { default } from
17
17
  declare module "node:buffer" { export * from "burger:buffer"; export { default } from "burger:buffer"; }
18
18
  declare module "buffer" { export * from "burger:buffer"; export { default } from "burger:buffer"; }
19
19
  declare module "bun:sqlite" { export * from "burger:sqlite"; export { default } from "burger:sqlite"; }
20
+ // Agent runtime pack (node-app-burger ADR 003, >= 0.3.3).
21
+ declare module "node:zlib" { export * from "burger:zlib"; export { default } from "burger:zlib"; }
22
+ declare module "zlib" { export * from "burger:zlib"; export { default } from "burger:zlib"; }
23
+ // Async context (node-app-burger ADR 004, >= 0.3.3).
24
+ declare module "node:async_hooks" { export * from "burger:async_hooks"; export { default } from "burger:async_hooks"; }
25
+ declare module "async_hooks" { export * from "burger:async_hooks"; export { default } from "burger:async_hooks"; }
20
26
  declare module "bun:test" { export * from "burger:test"; }
@@ -16,6 +16,38 @@ declare function clearTimeout(id: number | undefined): void;
16
16
  declare function setInterval(handler: (...args: any[]) => void, timeoutMs?: number, ...args: any[]): number;
17
17
  declare function clearInterval(id: number | undefined): void;
18
18
  declare function queueMicrotask(callback: () => void): void;
19
+ /** Agent runtime pack (node-app-burger ADR 003, >= 0.3.3): a zero-delay timer; the handle is a timer handle. */
20
+ declare function setImmediate(handler: (...args: any[]) => void, ...args: any[]): number;
21
+ declare function clearImmediate(id: number | undefined): void;
22
+
23
+ /**
24
+ * Agent runtime pack (node-app-burger ADR 003, >= 0.3.3): the WHATWG pair
25
+ * without the DOM. Listeners receive a plain `{ type: "abort", target,
26
+ * currentTarget }`; there is no EventTarget or Event class. The default
27
+ * reason is an Error named AbortError; a timeout's is named TimeoutError.
28
+ */
29
+ interface BurgerAbortEvent {
30
+ readonly type: "abort";
31
+ readonly target: AbortSignal;
32
+ readonly currentTarget: AbortSignal;
33
+ }
34
+ declare class AbortSignal {
35
+ private constructor();
36
+ readonly aborted: boolean;
37
+ readonly reason: any;
38
+ onabort: ((event: BurgerAbortEvent) => void) | null;
39
+ throwIfAborted(): void;
40
+ addEventListener(type: "abort", listener: ((event: BurgerAbortEvent) => void) | { handleEvent(event: BurgerAbortEvent): void }, options?: { once?: boolean; signal?: AbortSignal }): void;
41
+ removeEventListener(type: "abort", listener: ((event: BurgerAbortEvent) => void) | { handleEvent(event: BurgerAbortEvent): void }): void;
42
+ static abort(reason?: any): AbortSignal;
43
+ static timeout(milliseconds: number): AbortSignal;
44
+ static any(signals: Iterable<AbortSignal>): AbortSignal;
45
+ }
46
+ declare class AbortController {
47
+ constructor();
48
+ readonly signal: AbortSignal;
49
+ abort(reason?: any): void;
50
+ }
19
51
 
20
52
  declare class TextEncoder {
21
53
  constructor();
@@ -60,6 +92,10 @@ interface BurgerProcess {
60
92
  on(event: "unhandledRejection", listener: (reason: unknown) => void): void;
61
93
  on(event: string, listener: (...args: unknown[]) => void): void;
62
94
  off(event: string, listener: (...args: any[]) => void): void;
95
+ /** Agent runtime pack (node-app-burger ADR 003, >= 0.3.3): the listener runs for the next delivery only. */
96
+ once(event: "uncaughtException", listener: (error: unknown) => void): void;
97
+ once(event: "unhandledRejection", listener: (reason: unknown) => void): void;
98
+ once(event: string, listener: (...args: unknown[]) => void): void;
63
99
  nextTick(callback: (...args: any[]) => void, ...args: any[]): void;
64
100
  memoryUsage(): BurgerProcessMemoryUsage;
65
101
  }
@@ -47,6 +47,13 @@ declare module "burger:fs" {
47
47
  isDirectory(): boolean;
48
48
  readonly size: number;
49
49
  readonly mtimeMs: number;
50
+ /**
51
+ * Permission bits as Node reports them; `mode & 0o777` (agent runtime pack, node-app-burger
52
+ * >= 0.3.3). On an older runtime this field is `undefined`, so `mode & 0o777` is 0 and a
53
+ * "file is private" check would pass wrongly: depend on `node-app-burger (>= 0.3.3)` before
54
+ * relying on it.
55
+ */
56
+ readonly mode: number;
50
57
  }
51
58
 
52
59
  /**
@@ -298,6 +305,55 @@ declare module "burger:crypto" {
298
305
  export default crypto;
299
306
  }
300
307
 
308
+ /**
309
+ * Agent runtime pack (node-app-burger ADR 003, >= 0.3.3): the synchronous gzip
310
+ * pair of Node's `zlib`. Output is bounded like a whole-file read (half the
311
+ * app's memory limit) and by `maxOutputLength`; past either, `ERR_BUFFER_TOO_LARGE`.
312
+ */
313
+ declare module "burger:zlib" {
314
+ export interface GzipOptions {
315
+ /** -1 (zlib's default) or 0..9. */
316
+ level?: number;
317
+ }
318
+ export interface GunzipOptions {
319
+ /** At least 1 (else `ERR_OUT_OF_RANGE`); capped by the app's own limit. */
320
+ maxOutputLength?: number;
321
+ }
322
+ export const constants: {
323
+ Z_NO_COMPRESSION: 0;
324
+ Z_BEST_SPEED: 1;
325
+ Z_BEST_COMPRESSION: 9;
326
+ Z_DEFAULT_COMPRESSION: -1;
327
+ };
328
+ export function gzipSync(data: string | Uint8Array | ArrayBuffer | ArrayBufferView, options?: GzipOptions): import("burger:buffer").Buffer;
329
+ export function gunzipSync(data: string | Uint8Array | ArrayBuffer | ArrayBufferView, options?: GunzipOptions): import("burger:buffer").Buffer;
330
+ const zlib: {
331
+ gzipSync: typeof gzipSync;
332
+ gunzipSync: typeof gunzipSync;
333
+ constants: typeof constants;
334
+ };
335
+ export default zlib;
336
+ }
337
+
338
+ /** Node's `AsyncLocalStorage` on the async context the runtime carries (node-app-burger ADR 004,
339
+ * >= 0.3.3): a store set by `run` is still there after `await`, in `.then`, in a microtask and
340
+ * in a timer callback. Aliased from `async_hooks` and `node:async_hooks`. */
341
+ declare module "burger:async_hooks" {
342
+ export class AsyncLocalStorage<T> {
343
+ /** A function that runs `fn` in the async context current now. */
344
+ static bind<F extends (...args: never[]) => unknown>(fn: F): F;
345
+ /** A function that runs its argument in the async context current now. */
346
+ static snapshot(): <R, A extends unknown[]>(fn: (...args: A) => R, ...args: A) => R;
347
+ run<R, A extends unknown[]>(store: T, callback: (...args: A) => R, ...args: A): R;
348
+ exit<R, A extends unknown[]>(callback: (...args: A) => R, ...args: A): R;
349
+ enterWith(store: T): void;
350
+ getStore(): T | undefined;
351
+ disable(): void;
352
+ }
353
+ const asyncHooks: { AsyncLocalStorage: typeof AsyncLocalStorage };
354
+ export default asyncHooks;
355
+ }
356
+
301
357
  declare module "burger:buffer" {
302
358
  export type BufferEncoding = "utf8" | "utf-8" | "hex" | "base64" | "base64url" | "latin1" | "binary" | "ascii";
303
359
 
@@ -0,0 +1,9 @@
1
+ import type { InvocationContextStore } from "./types.js";
2
+ export type InvocationContextStoreCtor = new <T>() => InvocationContextStore<T>;
3
+ export declare const asyncContextReady: Promise<boolean>;
4
+ /** `AsyncLocalStorage` once loaded; `null` before that or on node-app-burger < 0.3.3. */
5
+ export declare function loadedAsyncLocalStorage(): InvocationContextStoreCtor | null;
6
+ /** `AsyncLocalStorage` once `load()` returns it, the synchronous store until then; it cannot switch inside a `run`, since the module loads in a job and no job runs during a synchronous `run`. */
7
+ export declare function delegatingInvocationContextStore<T>(load: () => InvocationContextStoreCtor | null): InvocationContextStore<T>;
8
+ /** Phase 1 behaviour for node-app-burger < 0.3.3: the store is visible only during the synchronous part of `fn`, so a nested call after the first `await` carries no `invocation_context_id` (the host files it as background work, never a wrong origin). */
9
+ export declare function synchronousInvocationContextStore<T>(): InvocationContextStore<T>;
@@ -32,13 +32,7 @@ export declare function assertHostEndpoint(): void;
32
32
  * await an `invoke_capability_result` frame that arrives later.
33
33
  */
34
34
  export declare function connectToHost(handlers: HostConnectionHandlers): HostConnection;
35
- /**
36
- * Burger Phase 1 has no `AsyncLocalStorage` (C6). The store is visible only
37
- * during the synchronous part of `fn`: a nested `invokeCapability` made
38
- * before the handler's first `await` carries `invocation_context_id`, later
39
- * ones carry none and the host classifies them as
40
- * `Background(AutonomousApp)` — never a wrong or elevated origin.
41
- */
35
+ /** The store each inbound handler runs in: `AsyncLocalStorage` on node-app-burger >= 0.3.3 (ADR 004), so nested calls carry `invocation_context_id` across `await` as on Bun; the Phase 1 store on an older runtime (`./burger-invocation-context.ts`). */
42
36
  export declare function createInvocationContextStore<T>(): InvocationContextStore<T>;
43
37
  /** @internal Exact QuickJS runtime sample used by the IPC timer and unit tests. */
44
38
  export declare function _sampleMemory(): AppMemorySample;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@econ-v1/app-sdk",
3
- "version": "7.6.10",
3
+ "version": "7.6.12",
4
4
  "description": "TypeScript SDK for building Node mini-app plugins (Bun runtime) on the Lightning-powered marketplace daemon",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "author": "Node contributors",