gemi 0.136.0 → 0.137.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/Agent.d.ts +48 -5
- package/dist/ai/Agent.d.ts.map +1 -1
- package/dist/ai/AgentController.d.ts +42 -2
- package/dist/ai/AgentController.d.ts.map +1 -1
- package/dist/ai/index.d.ts +3 -1
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +85 -18
- package/dist/ai/index.js.map +5 -4
- package/dist/ai/memory/AgentMemories.d.ts +226 -0
- package/dist/ai/memory/AgentMemories.d.ts.map +1 -0
- package/dist/ai/memory/AgentMemoryStore.d.ts +182 -0
- package/dist/ai/memory/AgentMemoryStore.d.ts.map +1 -0
- package/dist/ai/memory/DatabaseAgentMemoryStore.d.ts +76 -0
- package/dist/ai/memory/DatabaseAgentMemoryStore.d.ts.map +1 -0
- package/dist/ai/memory/contextBlock.d.ts +32 -0
- package/dist/ai/memory/contextBlock.d.ts.map +1 -0
- package/dist/ai/memory/index.d.ts +6 -0
- package/dist/ai/memory/index.d.ts.map +1 -0
- package/dist/ai/memory/runMemory.d.ts +355 -0
- package/dist/ai/memory/runMemory.d.ts.map +1 -0
- package/dist/ai/memory/safety.d.ts +34 -0
- package/dist/ai/memory/safety.d.ts.map +1 -0
- package/dist/ai/memory/search.d.ts +23 -0
- package/dist/ai/memory/search.d.ts.map +1 -0
- package/dist/app/index.js +1 -1
- package/dist/bun/plugin.js +1 -1
- package/dist/bun/preload.js +1 -1
- package/dist/{chunk-rnp5k8m3.js → chunk-038xtqpm.js} +2 -2
- package/dist/{chunk-rnp5k8m3.js.map → chunk-038xtqpm.js.map} +1 -1
- package/dist/{chunk-5pdgh9a1.js → chunk-26yghzet.js} +2 -2
- package/dist/{chunk-5pdgh9a1.js.map → chunk-26yghzet.js.map} +1 -1
- package/dist/{chunk-ha15x5ns.js → chunk-27xv8kty.js} +2 -2
- package/dist/{chunk-ha15x5ns.js.map → chunk-27xv8kty.js.map} +1 -1
- package/dist/{chunk-k2xeskp6.js → chunk-3jkem5gq.js} +2 -2
- package/dist/{chunk-k2xeskp6.js.map → chunk-3jkem5gq.js.map} +1 -1
- package/dist/{chunk-q15f5g86.js → chunk-46bwknb5.js} +3 -3
- package/dist/{chunk-q15f5g86.js.map → chunk-46bwknb5.js.map} +1 -1
- package/dist/{chunk-8sde8337.js → chunk-4jc7wbet.js} +2 -2
- package/dist/{chunk-8sde8337.js.map → chunk-4jc7wbet.js.map} +1 -1
- package/dist/{chunk-3dpmkxp7.js → chunk-4zjtbgnr.js} +2 -2
- package/dist/{chunk-3dpmkxp7.js.map → chunk-4zjtbgnr.js.map} +1 -1
- package/dist/{chunk-feajsgns.js → chunk-5benn2ys.js} +3 -3
- package/dist/{chunk-feajsgns.js.map → chunk-5benn2ys.js.map} +1 -1
- package/dist/{chunk-rzqft8q8.js → chunk-6qzyq0g5.js} +2 -2
- package/dist/{chunk-rzqft8q8.js.map → chunk-6qzyq0g5.js.map} +1 -1
- package/dist/{chunk-6qty7at2.js → chunk-78zfqt54.js} +2 -2
- package/dist/{chunk-6qty7at2.js.map → chunk-78zfqt54.js.map} +1 -1
- package/dist/{chunk-ysc7ykss.js → chunk-7d26eqv1.js} +2 -2
- package/dist/{chunk-ysc7ykss.js.map → chunk-7d26eqv1.js.map} +1 -1
- package/dist/{chunk-6fr6j338.js → chunk-7t7jh8t2.js} +2 -2
- package/dist/{chunk-6fr6j338.js.map → chunk-7t7jh8t2.js.map} +1 -1
- package/dist/{chunk-xvvsc58s.js → chunk-7vxeqxxr.js} +2 -2
- package/dist/{chunk-xvvsc58s.js.map → chunk-7vxeqxxr.js.map} +1 -1
- package/dist/{chunk-zyhmn3hy.js → chunk-80fjsb26.js} +3 -3
- package/dist/{chunk-zyhmn3hy.js.map → chunk-80fjsb26.js.map} +1 -1
- package/dist/{chunk-xymr3asa.js → chunk-85k70cme.js} +3 -3
- package/dist/{chunk-xymr3asa.js.map → chunk-85k70cme.js.map} +1 -1
- package/dist/{chunk-ka991yx4.js → chunk-8dmhbj4m.js} +2 -2
- package/dist/{chunk-ka991yx4.js.map → chunk-8dmhbj4m.js.map} +1 -1
- package/dist/{chunk-8ryrjtn0.js → chunk-8ef5c93d.js} +2 -2
- package/dist/{chunk-8ryrjtn0.js.map → chunk-8ef5c93d.js.map} +1 -1
- package/dist/{chunk-t33yh84d.js → chunk-8p4t8x9c.js} +2 -2
- package/dist/{chunk-t33yh84d.js.map → chunk-8p4t8x9c.js.map} +1 -1
- package/dist/{chunk-7nxnyw7x.js → chunk-965gfa41.js} +2 -2
- package/dist/{chunk-7nxnyw7x.js.map → chunk-965gfa41.js.map} +1 -1
- package/dist/{chunk-swwkdm75.js → chunk-974p7em0.js} +2 -2
- package/dist/{chunk-swwkdm75.js.map → chunk-974p7em0.js.map} +1 -1
- package/dist/{chunk-krk880my.js → chunk-9s203ks3.js} +2 -2
- package/dist/{chunk-krk880my.js.map → chunk-9s203ks3.js.map} +1 -1
- package/dist/{chunk-0eamc2tr.js → chunk-9wc53ywv.js} +2 -2
- package/dist/{chunk-0eamc2tr.js.map → chunk-9wc53ywv.js.map} +1 -1
- package/dist/{chunk-hb9hm8za.js → chunk-a2fhbstt.js} +3 -3
- package/dist/{chunk-hb9hm8za.js.map → chunk-a2fhbstt.js.map} +1 -1
- package/dist/{chunk-cxsvzqd4.js → chunk-aj2sr77y.js} +2 -2
- package/dist/{chunk-cxsvzqd4.js.map → chunk-aj2sr77y.js.map} +1 -1
- package/dist/{chunk-0gg4e94v.js → chunk-an1nja68.js} +2 -2
- package/dist/{chunk-0gg4e94v.js.map → chunk-an1nja68.js.map} +1 -1
- package/dist/{chunk-jy9dkgt0.js → chunk-ant9ck0r.js} +2 -2
- package/dist/{chunk-jy9dkgt0.js.map → chunk-ant9ck0r.js.map} +1 -1
- package/dist/chunk-atmw5c0q.js +28 -0
- package/dist/chunk-atmw5c0q.js.map +27 -0
- package/dist/{chunk-sa6cxt3g.js → chunk-bg0e39dk.js} +2 -2
- package/dist/{chunk-sa6cxt3g.js.map → chunk-bg0e39dk.js.map} +1 -1
- package/dist/{chunk-1awxdnb6.js → chunk-c0m8pcbd.js} +1 -1
- package/dist/{chunk-65j32dtn.js → chunk-c6c7p43e.js} +2 -2
- package/dist/{chunk-65j32dtn.js.map → chunk-c6c7p43e.js.map} +1 -1
- package/dist/{chunk-x9bk5s21.js → chunk-c83e4ghx.js} +2 -2
- package/dist/{chunk-x9bk5s21.js.map → chunk-c83e4ghx.js.map} +1 -1
- package/dist/{chunk-jgx8ggbz.js → chunk-cedmppcy.js} +2 -2
- package/dist/{chunk-jgx8ggbz.js.map → chunk-cedmppcy.js.map} +1 -1
- package/dist/{chunk-wrsf2abe.js → chunk-chyt9th4.js} +2 -2
- package/dist/{chunk-wrsf2abe.js.map → chunk-chyt9th4.js.map} +1 -1
- package/dist/{chunk-qfra7gah.js → chunk-d368es1y.js} +2 -2
- package/dist/{chunk-qfra7gah.js.map → chunk-d368es1y.js.map} +1 -1
- package/dist/{chunk-dt95z6et.js → chunk-d492ae5e.js} +2 -2
- package/dist/{chunk-dt95z6et.js.map → chunk-d492ae5e.js.map} +1 -1
- package/dist/{chunk-beb265c9.js → chunk-e440f645.js} +2 -2
- package/dist/{chunk-beb265c9.js.map → chunk-e440f645.js.map} +1 -1
- package/dist/{chunk-njpnstck.js → chunk-eqzxvfvt.js} +2 -2
- package/dist/{chunk-njpnstck.js.map → chunk-eqzxvfvt.js.map} +1 -1
- package/dist/{chunk-99a4e6zf.js → chunk-f9w78tbd.js} +2 -2
- package/dist/{chunk-99a4e6zf.js.map → chunk-f9w78tbd.js.map} +1 -1
- package/dist/chunk-fjw51b91.js +10 -0
- package/dist/{chunk-3gx7wcrt.js.map → chunk-fjw51b91.js.map} +3 -3
- package/dist/chunk-fs4ntgdr.js +5 -0
- package/dist/{chunk-47e7fbsp.js.map → chunk-fs4ntgdr.js.map} +1 -1
- package/dist/{chunk-gng5e7pd.js → chunk-fwmmy0jn.js} +1 -1
- package/dist/{chunk-mw7ft5bs.js → chunk-g22q8j2s.js} +2 -2
- package/dist/{chunk-mw7ft5bs.js.map → chunk-g22q8j2s.js.map} +1 -1
- package/dist/{chunk-z9xxthp1.js → chunk-ghbzre7k.js} +3 -3
- package/dist/{chunk-z9xxthp1.js.map → chunk-ghbzre7k.js.map} +1 -1
- package/dist/{chunk-x5hj0mqp.js → chunk-gq4fr0zn.js} +3 -3
- package/dist/{chunk-x5hj0mqp.js.map → chunk-gq4fr0zn.js.map} +1 -1
- package/dist/{chunk-x51tegk3.js → chunk-gqcmnyc8.js} +2 -2
- package/dist/{chunk-x51tegk3.js.map → chunk-gqcmnyc8.js.map} +1 -1
- package/dist/{chunk-x16ckgq1.js → chunk-h0ydk8cc.js} +2 -2
- package/dist/{chunk-x16ckgq1.js.map → chunk-h0ydk8cc.js.map} +1 -1
- package/dist/{chunk-m9vwg9j1.js → chunk-jys3n8xv.js} +3 -3
- package/dist/{chunk-m9vwg9j1.js.map → chunk-jys3n8xv.js.map} +1 -1
- package/dist/{chunk-3h37f124.js → chunk-kpb8xvrv.js} +2 -2
- package/dist/{chunk-3h37f124.js.map → chunk-kpb8xvrv.js.map} +1 -1
- package/dist/{chunk-mpqvmge4.js → chunk-kzdkpz04.js} +1 -1
- package/dist/{chunk-0rhf4g12.js → chunk-md6wfc1h.js} +3 -3
- package/dist/{chunk-0rhf4g12.js.map → chunk-md6wfc1h.js.map} +1 -1
- package/dist/{chunk-s025aycr.js → chunk-n2czjpz9.js} +2 -2
- package/dist/{chunk-s025aycr.js.map → chunk-n2czjpz9.js.map} +1 -1
- package/dist/{chunk-ff60bzvf.js → chunk-n7576zsr.js} +3 -3
- package/dist/{chunk-ff60bzvf.js.map → chunk-n7576zsr.js.map} +1 -1
- package/dist/{chunk-s782bzeq.js → chunk-nbfksexg.js} +2 -2
- package/dist/{chunk-s782bzeq.js.map → chunk-nbfksexg.js.map} +1 -1
- package/dist/{chunk-p82868xx.js → chunk-p1y58p84.js} +2 -2
- package/dist/{chunk-p82868xx.js.map → chunk-p1y58p84.js.map} +1 -1
- package/dist/{chunk-zv5qyrqg.js → chunk-p2c7z2nr.js} +2 -2
- package/dist/{chunk-zv5qyrqg.js.map → chunk-p2c7z2nr.js.map} +1 -1
- package/dist/{chunk-vnw91fe1.js → chunk-pv2mtg8n.js} +2 -2
- package/dist/{chunk-vnw91fe1.js.map → chunk-pv2mtg8n.js.map} +1 -1
- package/dist/{chunk-jx5zx48j.js → chunk-qfhcec6q.js} +2 -2
- package/dist/{chunk-jx5zx48j.js.map → chunk-qfhcec6q.js.map} +1 -1
- package/dist/{chunk-6hz63ts4.js → chunk-qk6vmvr2.js} +4 -4
- package/dist/{chunk-6hz63ts4.js.map → chunk-qk6vmvr2.js.map} +1 -1
- package/dist/{chunk-w1cksc5z.js → chunk-qvx8473q.js} +3 -3
- package/dist/{chunk-w1cksc5z.js.map → chunk-qvx8473q.js.map} +1 -1
- package/dist/{chunk-4278e429.js → chunk-rqb52m93.js} +2 -2
- package/dist/{chunk-4278e429.js.map → chunk-rqb52m93.js.map} +1 -1
- package/dist/{chunk-py1twqh8.js → chunk-skmdmqv7.js} +2 -2
- package/dist/{chunk-py1twqh8.js.map → chunk-skmdmqv7.js.map} +1 -1
- package/dist/{chunk-04tkpna8.js → chunk-t0p6zb29.js} +2 -2
- package/dist/{chunk-04tkpna8.js.map → chunk-t0p6zb29.js.map} +1 -1
- package/dist/{chunk-53rr32zm.js → chunk-ted0qjps.js} +1 -1
- package/dist/{chunk-hj88dcss.js → chunk-v4dp93qv.js} +3 -3
- package/dist/{chunk-hj88dcss.js.map → chunk-v4dp93qv.js.map} +1 -1
- package/dist/{chunk-33hdxe7v.js → chunk-vmr4d6hc.js} +1 -1
- package/dist/{chunk-3g5q0cj5.js → chunk-vz5rrcnh.js} +2 -2
- package/dist/{chunk-3g5q0cj5.js.map → chunk-vz5rrcnh.js.map} +1 -1
- package/dist/{chunk-pm8wjatv.js → chunk-w17p2k8g.js} +3 -3
- package/dist/{chunk-pm8wjatv.js.map → chunk-w17p2k8g.js.map} +1 -1
- package/dist/{chunk-j5g7qc5f.js → chunk-wbvb1hcx.js} +2 -2
- package/dist/{chunk-j5g7qc5f.js.map → chunk-wbvb1hcx.js.map} +1 -1
- package/dist/{chunk-t8xs9ptb.js → chunk-x1j7e46e.js} +2 -2
- package/dist/{chunk-t8xs9ptb.js.map → chunk-x1j7e46e.js.map} +1 -1
- package/dist/{chunk-jx2mgvvt.js → chunk-xwmy6fby.js} +3 -3
- package/dist/{chunk-jx2mgvvt.js.map → chunk-xwmy6fby.js.map} +1 -1
- package/dist/{chunk-z61dj480.js → chunk-y6gr3stt.js} +3 -3
- package/dist/{chunk-z61dj480.js.map → chunk-y6gr3stt.js.map} +1 -1
- package/dist/{chunk-4t41m5f1.js → chunk-yhp70t40.js} +2 -2
- package/dist/{chunk-4t41m5f1.js.map → chunk-yhp70t40.js.map} +1 -1
- package/dist/{chunk-zypmy8yq.js → chunk-z0jazehw.js} +2 -2
- package/dist/{chunk-zypmy8yq.js.map → chunk-z0jazehw.js.map} +1 -1
- package/dist/{chunk-541s0vkt.js → chunk-z19rwc6x.js} +5 -5
- package/dist/{chunk-541s0vkt.js.map → chunk-z19rwc6x.js.map} +1 -1
- package/dist/{chunk-gqgpwb88.js → chunk-z969a4nt.js} +2 -2
- package/dist/{chunk-gqgpwb88.js.map → chunk-z969a4nt.js.map} +1 -1
- package/dist/{chunk-hf492gg2.js → chunk-zj8y4ak5.js} +1 -1
- package/dist/{chunk-qpwb3gnh.js → chunk-zvzvgrrn.js} +2 -2
- package/dist/{chunk-qpwb3gnh.js.map → chunk-zvzvgrrn.js.map} +1 -1
- package/dist/config/index.js +1 -1
- package/dist/console/run.js +2 -2
- package/dist/console/run.js.map +1 -1
- package/dist/container/index.js +2 -2
- package/dist/container/index.js.map +1 -1
- package/dist/database/index.js +2 -2
- package/dist/database/index.js.map +1 -1
- package/dist/email/index.js +2 -2
- package/dist/email/index.js.map +1 -1
- package/dist/facades/index.js +2 -2
- package/dist/facades/index.js.map +1 -1
- package/dist/foundation/index.js +2 -2
- package/dist/foundation/index.js.map +1 -1
- package/dist/http/index.js +2 -2
- package/dist/http/index.js.map +1 -1
- package/dist/i18n/dictionaryRuntime.js +2 -2
- package/dist/i18n/dictionaryRuntime.js.map +1 -1
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/index.js.map +1 -1
- package/dist/kernel/index.js +2 -2
- package/dist/kernel/index.js.map +1 -1
- package/dist/orm/index.js +2 -2
- package/dist/orm/index.js.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/services/index.js +2 -2
- package/dist/services/index.js.map +1 -1
- package/dist/services/mcp/McpRegistry.d.ts.map +1 -1
- package/dist/services/queue/work.js +2 -2
- package/dist/services/queue/work.js.map +1 -1
- package/dist/stats/route-table.js +1 -1
- package/dist/support/index.js +2 -2
- package/dist/support/index.js.map +1 -1
- package/dist/vitest/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2cnawkke.js +0 -22
- package/dist/chunk-2cnawkke.js.map +0 -21
- package/dist/chunk-3gx7wcrt.js +0 -10
- package/dist/chunk-47e7fbsp.js +0 -5
- /package/dist/{chunk-1awxdnb6.js.map → chunk-c0m8pcbd.js.map} +0 -0
- /package/dist/{chunk-gng5e7pd.js.map → chunk-fwmmy0jn.js.map} +0 -0
- /package/dist/{chunk-mpqvmge4.js.map → chunk-kzdkpz04.js.map} +0 -0
- /package/dist/{chunk-53rr32zm.js.map → chunk-ted0qjps.js.map} +0 -0
- /package/dist/{chunk-33hdxe7v.js.map → chunk-vmr4d6hc.js.map} +0 -0
- /package/dist/{chunk-hf492gg2.js.map → chunk-zj8y4ak5.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import{constants as M}from"os";var Y=Symbol.for("gemi.server.shutdown");function Q(){let j=globalThis;return j[Y]??={shuttingDown:!1,drained:!1},j[Y]}function R(){return Q().shuttingDown}function f(){Q().shuttingDown=!0}function x(){Q().drained=!0}function W(j=process.env){let z={timeoutMs:U(j.GEMI_SHUTDOWN_TIMEOUT,20),delayMs:U(j.GEMI_SHUTDOWN_DELAY,0),providerTimeoutMs:U(j.GEMI_SHUTDOWN_PROVIDER_TIMEOUT,5)};if(z.delayMs>0&&z.delayMs>=z.timeoutMs)console.warn(`[gemi] GEMI_SHUTDOWN_DELAY (${z.delayMs/1000}s) leaves no time to drain within GEMI_SHUTDOWN_TIMEOUT (${z.timeoutMs/1000}s); in-flight requests will be abandoned on every shutdown. Raise the timeout.`);return z}function U(j,z){let B=j===void 0||j.trim()===""?NaN:Number(j);if(Number.isFinite(B)&&B>=0)return B*1000;if(j!==void 0)console.warn(`[gemi] Ignoring shutdown setting "${j}": expected a number of seconds.`);return z*1000}async function E(j){let{server:z,settings:B}=j,J=Date.now()+B.timeoutMs;f(),console.log(`[gemi] Shutting down: draining in-flight requests (up to ${B.timeoutMs/1000}s).`);let H=!0;if(z){if(B.delayMs>0)await _(Math.min(B.delayMs,J-Date.now()));let O=z.stop(),V=Promise.resolve();try{V=Promise.resolve(j.closeSockets?.()).catch(()=>{})}catch(F){console.error("[gemi] Closing the broadcast sockets failed:",F)}let X=J-Date.now(),$=j.closeSockets?Promise.race([O,Promise.all([V,y(z)])]):O;if(H=X>0?await G($,X):z.pendingRequests===0,!H)console.error(`[gemi] Shutdown grace period elapsed with ${z.pendingRequests} request(s) still in flight; abandoning them.`),z.stop(!0).catch(()=>{})}x();let P=await j.shutdownProviders({timeoutMs:B.providerTimeoutMs}),K=H&&P.failed.length===0&&P.timedOut.length===0;return console.log(`[gemi] Shutdown ${K?"complete":"finished with errors"}.`),K?0:1}function y(j){return new Promise((z)=>{let B=()=>{if(j.pendingRequests===0){z();return}setTimeout(B,50).unref?.()};B()})}async function G(j,z){if(z<=0)return!1;let B,J=await Promise.race([j.then(()=>!0,()=>!0),new Promise((H)=>{B=setTimeout(()=>H(!1),z)})]);return clearTimeout(B),J}function _(j){return new Promise((z)=>setTimeout(z,Math.max(0,j)))}function q(j){if(!R())return j;try{return j.headers.set("Connection","close"),j}catch{let z=new Response(j.body,j);return z.headers.set("Connection","close"),z}}function N(j){return async(z,B)=>{if(Q().drained)return new Response("Service Unavailable",{status:503,headers:{Connection:"close"}});return q(await j(z,B))}}var Z=Symbol.for("gemi.server.signalsInstalled"),w=1000;function D(j,z={}){let B=globalThis;if(B[Z])return;B[Z]=!0;let J=z.repeatWindowMs??w,H,P=(K)=>{if(H!==void 0){if(Date.now()-H<J)return;console.error(`[gemi] ${K} received again; exiting without waiting for the drain.`),process.exit(128+M.signals[K])}H=Date.now(),console.log(`[gemi] ${K} received.`),j().then((O)=>process.exit(O),(O)=>{console.error("[gemi] Shutdown failed:",O),process.exit(1)})};process.on("SIGTERM",P),process.on("SIGINT",P)}
|
|
3
|
-
export{R as
|
|
3
|
+
export{R as $k,f as al,W as bl,E as cl,q as dl,N as el,D as fl};
|
|
4
4
|
|
|
5
|
-
//# debugId=
|
|
5
|
+
//# debugId=5FDE9A637C65C8D164756E2164756E21
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
"import { constants } from \"node:os\";\nimport type { ShutdownReport } from \"../foundation/Application\";\nimport type { Instrumentation } from \"./types\";\n\n// On `globalThis` under a registry symbol rather than in a module variable, so\n// the flag an app's health route reads is the one the server set even when two\n// copies of this module are loaded — the built CLI bundles its own gemi (see\n// `app/App.ts`), and `bun --hot` re-evaluates every module on a reload.\nconst STATE = Symbol.for(\"gemi.server.shutdown\");\n\ntype ShutdownState = { shuttingDown: boolean; drained: boolean };\n\nfunction state(): ShutdownState {\n const global = globalThis as { [STATE]?: ShutdownState };\n global[STATE] ??= { shuttingDown: false, drained: false };\n return global[STATE];\n}\n\n/**\n * True from the moment this server process has been told to stop — before it\n * stops accepting connections — until it exits.\n *\n * gemi's built-in health route (`./health`) answers `503` while this is true,\n * and so should an app's own health route, so the platform's probe pulls the\n * instance while the in-flight requests are still draining. Every response sent in that window also carries\n * `Connection: close`, so a client that honours it opens its next request on a\n * new connection — one the load balancer can route elsewhere — instead of\n * reusing this one.\n */\nexport function isShuttingDown(): boolean {\n return state().shuttingDown;\n}\n\nexport function markShuttingDown() {\n state().shuttingDown = true;\n}\n\n/**\n * The request drain is over and the providers' `shutdown()` may be running:\n * from here on a request must not reach the app. See `serveForShutdown`.\n */\nexport function markDrained() {\n state().drained = true;\n}\n\n/** Test seam: a fresh process starts false, and so should each test. */\nexport function resetShuttingDown() {\n state().shuttingDown = false;\n state().drained = false;\n}\n\nexport type ShutdownSettings = {\n /**\n * From the signal to the end of the request drain, in milliseconds — the\n * delay below included. Requests still in flight when it runs out are\n * abandoned. `GEMI_SHUTDOWN_TIMEOUT`, in seconds; default 20. `0` means\n * \"close the listener and do not wait\": a shutdown with nothing in flight is\n * still a clean one.\n */\n timeoutMs: number;\n /**\n * How long to keep accepting new requests after `isShuttingDown()` turns\n * true, in milliseconds, so a health probe can see the `503` and the load\n * balancer stop routing here before the listener closes.\n * `GEMI_SHUTDOWN_DELAY`, in seconds; default 0.\n */\n delayMs: number;\n /**\n * The shared deadline for every provider's `shutdown()`, in milliseconds,\n * after the drain. `GEMI_SHUTDOWN_PROVIDER_TIMEOUT`, in seconds; default 5.\n * `0` skips the hooks — deliberately, so it is not reported as a failure.\n */\n providerTimeoutMs: number;\n};\n\n/**\n * 20s to drain plus 5s for providers is 25s: under the 30s that Kubernetes,\n * Azure Container Apps and ECS give by default between `SIGTERM` and `SIGKILL`,\n * with 5s left for the `gemi start` relay, the process exit and clock skew\n * between the platform's timer and ours. A platform with a shorter window\n * (Cloud Run's 10s, Fly's 5s) needs these lowered, not the other way round —\n * a drain that outlives the grace period ends in the same `SIGKILL` as no drain.\n *\n * The delay defaults to 0 because it only helps where a probe is watching, and\n * otherwise every shutdown would pay it for nothing.\n */\nexport function shutdownSettings(\n env: Record<string, string | undefined> = process.env,\n): ShutdownSettings {\n const settings = {\n timeoutMs: seconds(env.GEMI_SHUTDOWN_TIMEOUT, 20),\n delayMs: seconds(env.GEMI_SHUTDOWN_DELAY, 0),\n providerTimeoutMs: seconds(env.GEMI_SHUTDOWN_PROVIDER_TIMEOUT, 5),\n };\n // Warned, not clamped: the delay is sized to a probe, the timeout to the\n // platform's grace period, and which one is wrong only the operator knows.\n // Left alone, every shutdown spends the whole timeout in the delay and then\n // abandons whatever is in flight without draining it.\n if (settings.delayMs > 0 && settings.delayMs >= settings.timeoutMs) {\n console.warn(\n `[gemi] GEMI_SHUTDOWN_DELAY (${settings.delayMs / 1000}s) leaves no time to drain within GEMI_SHUTDOWN_TIMEOUT (${settings.timeoutMs / 1000}s); in-flight requests will be abandoned on every shutdown. Raise the timeout.`,\n );\n }\n return settings;\n}\n\nfunction seconds(value: string | undefined, fallback: number): number {\n const parsed = value === undefined || value.trim() === \"\" ? NaN : Number(value);\n if (Number.isFinite(parsed) && parsed >= 0) return parsed * 1000;\n if (value !== undefined) {\n console.warn(`[gemi] Ignoring shutdown setting \"${value}\": expected a number of seconds.`);\n }\n return fallback * 1000;\n}\n\n/** The part of `Bun.Server` a drain needs. */\nexport type Stoppable = {\n stop(closeActiveConnections?: boolean): Promise<void>;\n readonly pendingRequests: number;\n};\n\n/**\n * The shutdown sequence, in its order:\n *\n * 1. `isShuttingDown()` turns true — first, so the health route answers `503`\n * and responses carry `Connection: close` while the listener is still open.\n * 2. After `delayMs`, the listener closes (`server.stop()` without force):\n * new connections are refused, while every request in flight — a streamed\n * response included, to its last chunk — runs to completion.\n * Broadcast sockets are told `bye` and closed (`closeSockets`): a graceful\n * stop waits for open WebSockets, which never close on their own.\n * 3. That completion is awaited until `timeoutMs` from the start.\n * 4. From here a request is refused with a `503` before it reaches the app\n * (`serveForShutdown`), and every provider's `shutdown()` runs, reverse\n * order, `providerTimeoutMs`.\n *\n * Resolves with the exit code: 0 when every step finished in time, 1 when the\n * drain was cut short or a provider failed or overran.\n *\n * Two things `stop()` does not do, both measured on Bun 1.3.14, and both why\n * the process exit that follows is what actually ends the server:\n *\n * - It does not close a kept-alive connection. One that is idle when the\n * listener closes stays open, and a request sent down it afterwards is\n * served. That is what the `Connection: close` on every response in the\n * window is for: a client (or a proxy in front) that honours it opens its\n * next request on a new connection, which the closed listener refuses. A\n * client that does not honour it is what step 4's `503` is for — Bun does\n * not close the socket after a `Connection: close` response either (#566).\n * - `stop(true)` issued after a graceful `stop()` does not cut the remaining\n * requests off; it waits for the same ones. It is still called when the\n * drain times out, for a Bun that does, but nothing here depends on it. Nor\n * does it close an idle kept-alive connection. Only a `stop(true)` issued\n * *first* does that, and it cuts off the requests in flight with it, which\n * is the drain given up — so the idle ones are refused, not closed.\n */\nexport async function drain(params: {\n server: Stoppable | undefined;\n /**\n * Says `bye` to the broadcast sockets and closes them, right after the\n * listener closes, and resolves once they are closed or cut. A graceful\n * `stop()` waits for open WebSockets, which otherwise never close on their\n * own.\n */\n closeSockets?: () => void | Promise<void>;\n shutdownProviders: (options: { timeoutMs: number }) => Promise<ShutdownReport>;\n settings: ShutdownSettings;\n}): Promise<number> {\n const { server, settings } = params;\n const deadline = Date.now() + settings.timeoutMs;\n\n markShuttingDown();\n console.log(\n `[gemi] Shutting down: draining in-flight requests (up to ${settings.timeoutMs / 1000}s).`,\n );\n\n let drained = true;\n if (server) {\n if (settings.delayMs > 0) {\n await sleep(Math.min(settings.delayMs, deadline - Date.now()));\n }\n const stopped = server.stop();\n let socketsClosed: Promise<unknown> = Promise.resolve();\n try {\n socketsClosed = Promise.resolve(params.closeSockets?.()).catch(() => {});\n } catch (error) {\n console.error(\"[gemi] Closing the broadcast sockets failed:\", error);\n }\n // No time left to wait — a `GEMI_SHUTDOWN_TIMEOUT` of 0, or a delay that\n // spent all of it — is \"do not wait for what is in flight\", and that is\n // only a failure when something *is* in flight. Reading it as one made\n // every clean shutdown log an abandonment and exit 1 for the operator who\n // zeroed the budget to fit a 5s grace period, with nothing to abandon.\n const remaining = deadline - Date.now();\n // With broadcast sockets, the stop's own promise has been seen to stay\n // pending for good after every request finished and every socket was\n // closed or terminated (Bun 1.4.2 on a loaded Linux CI runner, with its\n // `pendingWebSockets` stuck above 0). So the drain also ends on its real\n // condition: no request in flight, and the hub's sockets closed or cut.\n const done = params.closeSockets\n ? Promise.race([stopped, Promise.all([socketsClosed, noRequestInFlight(server)])])\n : stopped;\n drained =\n remaining > 0 ? await settlesWithin(done, remaining) : server.pendingRequests === 0;\n if (!drained) {\n console.error(\n `[gemi] Shutdown grace period elapsed with ${server.pendingRequests} request(s) still in flight; abandoning them.`,\n );\n void server.stop(true).catch(() => {});\n }\n }\n\n // Whether or not the drain finished: a request that arrives now, down a\n // kept-alive connection the listener's close left open, would run against\n // providers that are being shut down underneath it.\n markDrained();\n const report = await params.shutdownProviders({ timeoutMs: settings.providerTimeoutMs });\n const clean = drained && report.failed.length === 0 && report.timedOut.length === 0;\n console.log(`[gemi] Shutdown ${clean ? \"complete\" : \"finished with errors\"}.`);\n return clean ? 0 : 1;\n}\n\n/**\n * Resolves once `server` has no request in flight. A streamed response counts\n * until its last chunk (measured on Bun 1.4, macOS and Linux).\n */\nfunction noRequestInFlight(server: Stoppable): Promise<void> {\n return new Promise((resolve) => {\n const check = () => {\n if (server.pendingRequests === 0) {\n resolve();\n return;\n }\n const timer = setTimeout(check, 50);\n (timer as { unref?: () => void }).unref?.();\n };\n check();\n });\n}\n\nasync function settlesWithin(promise: Promise<unknown>, ms: number): Promise<boolean> {\n // `drain` decides for itself what a budget that is already spent means, so\n // this is only a guard: a race against `setTimeout(0)` is a coin toss, and\n // \"did not settle within no time at all\" is the honest answer to it.\n if (ms <= 0) return false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const result = await Promise.race([\n promise.then(\n () => true,\n () => true,\n ),\n new Promise<false>((resolve) => {\n timer = setTimeout(() => resolve(false), ms);\n }),\n ]);\n clearTimeout(timer);\n return result;\n}\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));\n}\n\n/**\n * `Connection: close` on a response sent while shutting down, so the client's\n * next request opens a connection — which the load balancer can send elsewhere\n * — instead of reusing this one.\n *\n * The spec makes some responses' headers immutable (a `Response.redirect`, a\n * proxied `fetch`), and setting one throws. Bun 1.3.14 lets both be set, so\n * the copy is for a Bun that follows the spec — a throw here would turn every\n * such response in the drain window into a 500.\n */\nexport function closeConnectionWhileShuttingDown(res: Response): Response {\n if (!isShuttingDown()) return res;\n try {\n res.headers.set(\"Connection\", \"close\");\n return res;\n } catch {\n const copy = new Response(res.body, res);\n copy.headers.set(\"Connection\", \"close\");\n return copy;\n }\n}\n\n/**\n * What every response goes through while this process serves: the app's\n * instrumentation, with the two changes a shutdown makes to it.\n *\n * - While the requests in flight drain, a response carries `Connection: close`\n * (`closeConnectionWhileShuttingDown`).\n * - Once they have drained, a request is answered `503` with\n * `Connection: close` and reaches neither the app nor its instrumentation.\n * The listener is closed by then, so only a kept-alive connection can still\n * deliver one, and `server.stop()` leaves those open. Serving it would run a\n * handler against providers whose `shutdown()` is closing the pool, the\n * queue or the cache it uses — until the process exits. The instrumentation\n * is skipped too because it is app code, and a tracer or error reporter is\n * exactly what a provider flushes and closes at this point.\n */\nexport function serveForShutdown(instrumentation: Instrumentation): Instrumentation {\n return async (req, next) => {\n if (state().drained) {\n return new Response(\"Service Unavailable\", {\n status: 503,\n headers: { Connection: \"close\" },\n });\n }\n return closeConnectionWhileShuttingDown(await instrumentation(req, next));\n };\n}\n\n// Installed once per process, not once per `Server`: a listener per instance\n// would each start a shutdown of its own, and read the other's signal as the\n// second one.\nconst SIGNALS_INSTALLED = Symbol.for(\"gemi.server.signalsInstalled\");\n\n/**\n * A repeat of the first signal inside this window is the same shutdown\n * delivered twice, not an operator asking to skip the drain. One shutdown\n * routinely arrives more than once, milliseconds apart: Ctrl+C on\n * `bun run start` reaches the server directly (the whole foreground group is\n * signalled), and again through `gemi start`'s relay — twice over, since\n * `bun run` forwards it to `gemi start` too. systemd's default\n * `KillMode=control-group` and `tini -g` do the same to every process in the\n * group. A person pressing Ctrl+C again is well outside a second.\n */\nconst REPEAT_WINDOW_MS = 1000;\n\n/**\n * `SIGTERM` or `SIGINT` runs `stop` and exits with the code it resolves with.\n * Another signal of either kind, more than `repeatWindowMs` after the first,\n * exits at once with `128 + n` — an operator pressing Ctrl+C again does not\n * want to wait out the grace period. Without a listener the first signal would\n * do that too: the default action for both is to terminate the process on the\n * spot.\n */\nexport function installShutdownSignals(\n stop: () => Promise<number>,\n options: { repeatWindowMs?: number } = {},\n) {\n const global = globalThis as { [SIGNALS_INSTALLED]?: boolean };\n if (global[SIGNALS_INSTALLED]) return;\n global[SIGNALS_INSTALLED] = true;\n\n const repeatWindowMs = options.repeatWindowMs ?? REPEAT_WINDOW_MS;\n let receivedAt: number | undefined;\n const onSignal = (signal: \"SIGTERM\" | \"SIGINT\") => {\n if (receivedAt !== undefined) {\n if (Date.now() - receivedAt < repeatWindowMs) return;\n console.error(`[gemi] ${signal} received again; exiting without waiting for the drain.`);\n process.exit(128 + constants.signals[signal]);\n }\n receivedAt = Date.now();\n console.log(`[gemi] ${signal} received.`);\n stop().then(\n (code) => process.exit(code),\n (error) => {\n console.error(\"[gemi] Shutdown failed:\", error);\n process.exit(1);\n },\n );\n };\n process.on(\"SIGTERM\", onSignal);\n process.on(\"SIGINT\", onSignal);\n}\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
8
|
+
"debugId": "5FDE9A637C65C8D164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|