termbeam 1.17.3 → 1.17.4

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.
Files changed (58) hide show
  1. package/package.json +1 -1
  2. package/public/assets/{_basePickBy-BpcK6jhC.js → _basePickBy-0kpFmj0i.js} +1 -1
  3. package/public/assets/{_baseUniq-CmudMx6k.js → _baseUniq-ClnVVws1.js} +1 -1
  4. package/public/assets/{arc-BBjpe_hN.js → arc-Dzz7iV1B.js} +1 -1
  5. package/public/assets/{architectureDiagram-2XIMDMQ5-BFCoYW28.js → architectureDiagram-2XIMDMQ5-0LiO_Haj.js} +1 -1
  6. package/public/assets/{blockDiagram-WCTKOSBZ-Dh31wJRm.js → blockDiagram-WCTKOSBZ-CfD0B0tq.js} +1 -1
  7. package/public/assets/{c4Diagram-IC4MRINW-CPV76ZUM.js → c4Diagram-IC4MRINW-3ppw40cY.js} +1 -1
  8. package/public/assets/channel-CLKml9tB.js +1 -0
  9. package/public/assets/{chunk-4BX2VUAB-eU5lnLp-.js → chunk-4BX2VUAB-4yc1d8Nd.js} +1 -1
  10. package/public/assets/{chunk-55IACEB6-CRSrEoDB.js → chunk-55IACEB6-DJVrjvbz.js} +1 -1
  11. package/public/assets/{chunk-FMBD7UC4-cK52FAx0.js → chunk-FMBD7UC4-v0DR1X_4.js} +1 -1
  12. package/public/assets/{chunk-JSJVCQXG-CudZY5_F.js → chunk-JSJVCQXG-vfzfWdiO.js} +1 -1
  13. package/public/assets/{chunk-KX2RTZJC-BZlXzthI.js → chunk-KX2RTZJC-rUuzVVLE.js} +1 -1
  14. package/public/assets/{chunk-NQ4KR5QH-BP6XJFdX.js → chunk-NQ4KR5QH-Bg0iNBVP.js} +1 -1
  15. package/public/assets/{chunk-QZHKN3VN-DDY6gqIZ.js → chunk-QZHKN3VN-BhaEnvkv.js} +1 -1
  16. package/public/assets/{chunk-WL4C6EOR-DY15q7Tk.js → chunk-WL4C6EOR-BjZnqD0U.js} +1 -1
  17. package/public/assets/classDiagram-VBA2DB6C-CcqrO3eb.js +1 -0
  18. package/public/assets/classDiagram-v2-RAHNMMFH-CcqrO3eb.js +1 -0
  19. package/public/assets/clone-Crb49TJI.js +1 -0
  20. package/public/assets/{cose-bilkent-S5V4N54A-CTeXZoSq.js → cose-bilkent-S5V4N54A-DUAC9S22.js} +1 -1
  21. package/public/assets/{dagre-KLK3FWXG-BOfJIpm3.js → dagre-KLK3FWXG-BMtFOQy3.js} +1 -1
  22. package/public/assets/{diagram-E7M64L7V-yhW3nXxA.js → diagram-E7M64L7V-2MENMB7x.js} +1 -1
  23. package/public/assets/{diagram-IFDJBPK2-B7r-HJa0.js → diagram-IFDJBPK2-CLQVFUVj.js} +1 -1
  24. package/public/assets/{diagram-P4PSJMXO-Cl1dGq__.js → diagram-P4PSJMXO-CU7V3fXy.js} +1 -1
  25. package/public/assets/{erDiagram-INFDFZHY-xb7jd7iV.js → erDiagram-INFDFZHY-wCvCuo-B.js} +1 -1
  26. package/public/assets/{flowDiagram-PKNHOUZH-7__LLCFp.js → flowDiagram-PKNHOUZH-Boz3lacJ.js} +1 -1
  27. package/public/assets/{ganttDiagram-A5KZAMGK-BRH4oYpz.js → ganttDiagram-A5KZAMGK-CWqdZ7OI.js} +1 -1
  28. package/public/assets/{gitGraphDiagram-K3NZZRJ6-CZ0c5437.js → gitGraphDiagram-K3NZZRJ6-CqevZOIa.js} +1 -1
  29. package/public/assets/{graph-CaPDDY3I.js → graph-RqkgQOtG.js} +1 -1
  30. package/public/assets/{index-7DPrKRHX.css → index-OLhvO-lo.css} +1 -1
  31. package/public/assets/{index-pqtccC7s.js → index-krC-nFgj.js} +4 -4
  32. package/public/assets/{infoDiagram-LFFYTUFH-B50sX0Jk.js → infoDiagram-LFFYTUFH-B2kINdu2.js} +1 -1
  33. package/public/assets/{ishikawaDiagram-PHBUUO56-BTx9nUR_.js → ishikawaDiagram-PHBUUO56-ax9eusTy.js} +1 -1
  34. package/public/assets/{journeyDiagram-4ABVD52K-DOKjshE4.js → journeyDiagram-4ABVD52K-Dwd7nrwc.js} +1 -1
  35. package/public/assets/{kanban-definition-K7BYSVSG-DlsqM5ac.js → kanban-definition-K7BYSVSG-Cfjl6s7S.js} +1 -1
  36. package/public/assets/{layout-C4hgRWBc.js → layout-DJKj_FTS.js} +1 -1
  37. package/public/assets/{linear-pPVtYfoA.js → linear-CAYODrs8.js} +1 -1
  38. package/public/assets/{mindmap-definition-YRQLILUH-KXwvxrd9.js → mindmap-definition-YRQLILUH-1Tw3mDSx.js} +1 -1
  39. package/public/assets/{pieDiagram-SKSYHLDU-Db_hnpTO.js → pieDiagram-SKSYHLDU-DjBXbSpO.js} +1 -1
  40. package/public/assets/{quadrantDiagram-337W2JSQ-DBgEkZee.js → quadrantDiagram-337W2JSQ-v7ZVRO3r.js} +1 -1
  41. package/public/assets/{requirementDiagram-Z7DCOOCP-DzYp2J9t.js → requirementDiagram-Z7DCOOCP-kGDKpJ88.js} +1 -1
  42. package/public/assets/{sankeyDiagram-WA2Y5GQK-DqRGFuVJ.js → sankeyDiagram-WA2Y5GQK-BRHTtm5o.js} +1 -1
  43. package/public/assets/{sequenceDiagram-2WXFIKYE-CCATgMDC.js → sequenceDiagram-2WXFIKYE-Cd4PXvbK.js} +1 -1
  44. package/public/assets/{stateDiagram-RAJIS63D-DBbQtnkh.js → stateDiagram-RAJIS63D-DBaX5xL4.js} +1 -1
  45. package/public/assets/stateDiagram-v2-FVOUBMTO-oq90yqVz.js +1 -0
  46. package/public/assets/{timeline-definition-YZTLITO2-AB47RPpS.js → timeline-definition-YZTLITO2-C1TqIxxb.js} +1 -1
  47. package/public/assets/{treemap-KZPCXAKY-BwGtQefY.js → treemap-KZPCXAKY-FdKKPGme.js} +1 -1
  48. package/public/assets/{vennDiagram-LZ73GAT5-CQy8NUxW.js → vennDiagram-LZ73GAT5-Ztcsx3HA.js} +1 -1
  49. package/public/assets/{xychartDiagram-JWTSCODW-D1U0PBps.js → xychartDiagram-JWTSCODW-Dn4p5BUd.js} +1 -1
  50. package/public/index.html +2 -2
  51. package/public/sw.js +1 -1
  52. package/src/server/index.js +18 -1
  53. package/src/tunnel/index.js +234 -28
  54. package/public/assets/channel-spGqRIlf.js +0 -1
  55. package/public/assets/classDiagram-VBA2DB6C-CwKQYDdP.js +0 -1
  56. package/public/assets/classDiagram-v2-RAHNMMFH-CwKQYDdP.js +0 -1
  57. package/public/assets/clone-BQhUsBH5.js +0 -1
  58. package/public/assets/stateDiagram-v2-FVOUBMTO-Dr2a5PWq.js +0 -1
package/public/sw.js CHANGED
@@ -1,2 +1,2 @@
1
1
  try{self["workbox:core:7.3.0"]&&_()}catch{}const G=(s,...e)=>{let t=s;return e.length>0&&(t+=` :: ${JSON.stringify(e)}`),t},Q=G;class h extends Error{constructor(e,t){const n=Q(e,t);super(n),this.name=e,this.details=t}}const d={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:typeof registration<"u"?registration.scope:""},E=s=>[d.prefix,s,d.suffix].filter(e=>e&&e.length>0).join("-"),z=s=>{for(const e of Object.keys(d))s(e)},b={updateDetails:s=>{z(e=>{typeof s[e]=="string"&&(d[e]=s[e])})},getGoogleAnalyticsName:s=>s||E(d.googleAnalytics),getPrecacheName:s=>s||E(d.precache),getPrefix:()=>d.prefix,getRuntimeName:s=>s||E(d.runtime),getSuffix:()=>d.suffix};function N(s,e){const t=e();return s.waitUntil(t),t}try{self["workbox:precaching:7.3.0"]&&_()}catch{}const J="__WB_REVISION__";function X(s){if(!s)throw new h("add-to-cache-list-unexpected-type",{entry:s});if(typeof s=="string"){const r=new URL(s,location.href);return{cacheKey:r.href,url:r.href}}const{revision:e,url:t}=s;if(!t)throw new h("add-to-cache-list-unexpected-type",{entry:s});if(!e){const r=new URL(t,location.href);return{cacheKey:r.href,url:r.href}}const n=new URL(t,location.href),a=new URL(t,location.href);return n.searchParams.set(J,e),{cacheKey:n.href,url:a.href}}class Y{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type==="install"&&t&&t.originalRequest&&t.originalRequest instanceof Request){const a=t.originalRequest.url;n?this.notUpdatedURLs.push(a):this.updatedURLs.push(a)}return n}}}class Z{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:t,params:n})=>{const a=(n==null?void 0:n.cacheKey)||this._precacheController.getCacheKeyForURL(t.url);return a?new Request(a,{headers:t.headers}):t},this._precacheController=e}}let m;function ee(){if(m===void 0){const s=new Response("");if("body"in s)try{new Response(s.body),m=!0}catch{m=!1}m=!1}return m}async function te(s,e){let t=null;if(s.url&&(t=new URL(s.url).origin),t!==self.location.origin)throw new h("cross-origin-copy-response",{origin:t});const n=s.clone(),r={headers:new Headers(n.headers),status:n.status,statusText:n.statusText},i=ee()?n.body:await n.blob();return new Response(i,r)}const se=s=>new URL(String(s),location.href).href.replace(new RegExp(`^${location.origin}`),"");function M(s,e){const t=new URL(s);for(const n of e)t.searchParams.delete(n);return t.href}async function ne(s,e,t,n){const a=M(e.url,t);if(e.url===a)return s.match(e,n);const r=Object.assign(Object.assign({},n),{ignoreSearch:!0}),i=await s.keys(e,r);for(const c of i){const o=M(c.url,t);if(a===o)return s.match(c,n)}}class ae{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}}const B=new Set;async function re(){for(const s of B)await s()}function ie(s){return new Promise(e=>setTimeout(e,s))}try{self["workbox:strategies:7.3.0"]&&_()}catch{}function C(s){return typeof s=="string"?new Request(s):s}class ce{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new ae,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(const n of this._plugins)this._pluginStateMap.set(n,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){const{event:t}=this;let n=C(e);if(n.mode==="navigate"&&t instanceof FetchEvent&&t.preloadResponse){const i=await t.preloadResponse;if(i)return i}const a=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const i of this.iterateCallbacks("requestWillFetch"))n=await i({request:n.clone(),event:t})}catch(i){if(i instanceof Error)throw new h("plugin-error-request-will-fetch",{thrownErrorMessage:i.message})}const r=n.clone();try{let i;i=await fetch(n,n.mode==="navigate"?void 0:this._strategy.fetchOptions);for(const c of this.iterateCallbacks("fetchDidSucceed"))i=await c({event:t,request:r,response:i});return i}catch(i){throw a&&await this.runCallbacks("fetchDidFail",{error:i,event:t,originalRequest:a.clone(),request:r.clone()}),i}}async fetchAndCachePut(e){const t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){const t=C(e);let n;const{cacheName:a,matchOptions:r}=this._strategy,i=await this.getCacheKey(t,"read"),c=Object.assign(Object.assign({},r),{cacheName:a});n=await caches.match(i,c);for(const o of this.iterateCallbacks("cachedResponseWillBeUsed"))n=await o({cacheName:a,matchOptions:r,cachedResponse:n,request:i,event:this.event})||void 0;return n}async cachePut(e,t){const n=C(e);await ie(0);const a=await this.getCacheKey(n,"write");if(!t)throw new h("cache-put-with-no-response",{url:se(a.url)});const r=await this._ensureResponseSafeToCache(t);if(!r)return!1;const{cacheName:i,matchOptions:c}=this._strategy,o=await self.caches.open(i),l=this.hasCallback("cacheDidUpdate"),g=l?await ne(o,a.clone(),["__WB_REVISION__"],c):null;try{await o.put(a,l?r.clone():r)}catch(u){if(u instanceof Error)throw u.name==="QuotaExceededError"&&await re(),u}for(const u of this.iterateCallbacks("cacheDidUpdate"))await u({cacheName:i,oldResponse:g,newResponse:r.clone(),request:a,event:this.event});return!0}async getCacheKey(e,t){const n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let a=e;for(const r of this.iterateCallbacks("cacheKeyWillBeUsed"))a=C(await r({mode:t,request:a,event:this.event,params:this.params}));this._cacheKeys[n]=a}return this._cacheKeys[n]}hasCallback(e){for(const t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(const n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(const t of this._strategy.plugins)if(typeof t[e]=="function"){const n=this._pluginStateMap.get(t);yield r=>{const i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){const e=this._extendLifetimePromises.splice(0),n=(await Promise.allSettled(e)).find(a=>a.status==="rejected");if(n)throw n.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(const a of this.iterateCallbacks("cacheWillUpdate"))if(t=await a({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}}class W{constructor(e={}){this.cacheName=b.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){const[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});const t=e.event,n=typeof e.request=="string"?new Request(e.request):e.request,a="params"in e?e.params:void 0,r=new ce(this,{event:t,request:n,params:a}),i=this._getResponse(r,n,t),c=this._awaitComplete(i,r,n,t);return[i,c]}async _getResponse(e,t,n){await e.runCallbacks("handlerWillStart",{event:n,request:t});let a;try{if(a=await this._handle(t,e),!a||a.type==="error")throw new h("no-response",{url:t.url})}catch(r){if(r instanceof Error){for(const i of e.iterateCallbacks("handlerDidError"))if(a=await i({error:r,event:n,request:t}),a)break}if(!a)throw r}for(const r of e.iterateCallbacks("handlerWillRespond"))a=await r({event:n,request:t,response:a});return a}async _awaitComplete(e,t,n,a){let r,i;try{r=await e}catch{}try{await t.runCallbacks("handlerDidRespond",{event:a,request:n,response:r}),await t.doneWaiting()}catch(c){c instanceof Error&&(i=c)}if(await t.runCallbacks("handlerDidComplete",{event:a,request:n,response:r,error:i}),t.destroy(),i)throw i}}class p extends W{constructor(e={}){e.cacheName=b.getPrecacheName(e.cacheName),super(e),this._fallbackToNetwork=e.fallbackToNetwork!==!1,this.plugins.push(p.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){const n=await t.cacheMatch(e);return n||(t.event&&t.event.type==="install"?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,t){let n;const a=t.params||{};if(this._fallbackToNetwork){const r=a.integrity,i=e.integrity,c=!i||i===r;n=await t.fetch(new Request(e,{integrity:e.mode!=="no-cors"?i||r:void 0})),r&&c&&e.mode!=="no-cors"&&(this._useDefaultCacheabilityPluginIfNeeded(),await t.cachePut(e,n.clone()))}else throw new h("missing-precache-entry",{cacheName:this.cacheName,url:e.url});return n}async _handleInstall(e,t){this._useDefaultCacheabilityPluginIfNeeded();const n=await t.fetch(e);if(!await t.cachePut(e,n.clone()))throw new h("bad-precaching-response",{url:e.url,status:n.status});return n}_useDefaultCacheabilityPluginIfNeeded(){let e=null,t=0;for(const[n,a]of this.plugins.entries())a!==p.copyRedirectedCacheableResponsesPlugin&&(a===p.defaultPrecacheCacheabilityPlugin&&(e=n),a.cacheWillUpdate&&t++);t===0?this.plugins.push(p.defaultPrecacheCacheabilityPlugin):t>1&&e!==null&&this.plugins.splice(e,1)}}p.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:s}){return!s||s.status>=400?null:s}};p.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:s}){return s.redirected?await te(s):s}};class oe{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new p({cacheName:b.getPrecacheName(e),plugins:[...t,new Z({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this._installAndActiveListenersAdded=!0)}addToCacheList(e){const t=[];for(const n of e){typeof n=="string"?t.push(n):n&&n.revision===void 0&&t.push(n.url);const{cacheKey:a,url:r}=X(n),i=typeof n!="string"&&n.revision?"reload":"default";if(this._urlsToCacheKeys.has(r)&&this._urlsToCacheKeys.get(r)!==a)throw new h("add-to-cache-list-conflicting-entries",{firstEntry:this._urlsToCacheKeys.get(r),secondEntry:a});if(typeof n!="string"&&n.integrity){if(this._cacheKeysToIntegrities.has(a)&&this._cacheKeysToIntegrities.get(a)!==n.integrity)throw new h("add-to-cache-list-conflicting-integrities",{url:r});this._cacheKeysToIntegrities.set(a,n.integrity)}if(this._urlsToCacheKeys.set(r,a),this._urlsToCacheModes.set(r,i),t.length>0){const c=`Workbox is precaching URLs without revision info: ${t.join(", ")}
2
- This is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(c)}}}install(e){return N(e,async()=>{const t=new Y;this.strategy.plugins.push(t);for(const[r,i]of this._urlsToCacheKeys){const c=this._cacheKeysToIntegrities.get(i),o=this._urlsToCacheModes.get(r),l=new Request(r,{integrity:c,cache:o,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:i},request:l,event:e}))}const{updatedURLs:n,notUpdatedURLs:a}=t;return{updatedURLs:n,notUpdatedURLs:a}})}activate(e){return N(e,async()=>{const t=await self.caches.open(this.strategy.cacheName),n=await t.keys(),a=new Set(this._urlsToCacheKeys.values()),r=[];for(const i of n)a.has(i.url)||(await t.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){const t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){const t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){const t=this.getCacheKeyForURL(e);if(!t)throw new h("non-precached-url",{url:e});return n=>(n.request=new Request(e),n.params=Object.assign({cacheKey:t},n.params),this.strategy.handle(n))}}let L;const j=()=>(L||(L=new oe),L);try{self["workbox:routing:7.3.0"]&&_()}catch{}const F="GET",x=s=>s&&typeof s=="object"?s:{handle:s};class R{constructor(e,t,n=F){this.handler=x(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=x(e)}}class le extends R{constructor(e,t,n){const a=({url:r})=>{const i=e.exec(r.href);if(i&&!(r.origin!==location.origin&&i.index!==0))return i.slice(1)};super(a,t,n)}}class he{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",(e=>{const{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener("message",(e=>{if(e.data&&e.data.type==="CACHE_URLS"){const{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(a=>{typeof a=="string"&&(a=[a]);const r=new Request(...a);return this.handleRequest({request:r,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){const n=new URL(e.url,location.href);if(!n.protocol.startsWith("http"))return;const a=n.origin===location.origin,{params:r,route:i}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:n});let c=i&&i.handler;const o=e.method;if(!c&&this._defaultHandlerMap.has(o)&&(c=this._defaultHandlerMap.get(o)),!c)return;let l;try{l=c.handle({url:n,request:e,event:t,params:r})}catch(u){l=Promise.reject(u)}const g=i&&i.catchHandler;return l instanceof Promise&&(this._catchHandler||g)&&(l=l.catch(async u=>{if(g)try{return await g.handle({url:n,request:e,event:t,params:r})}catch(I){I instanceof Error&&(u=I)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw u})),l}findMatchingRoute({url:e,sameOrigin:t,request:n,event:a}){const r=this._routes.get(n.method)||[];for(const i of r){let c;const o=i.match({url:e,sameOrigin:t,request:n,event:a});if(o)return c=o,(Array.isArray(c)&&c.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o=="boolean")&&(c=void 0),{route:i,params:c}}return{}}setDefaultHandler(e,t=F){this._defaultHandlerMap.set(t,x(e))}setCatchHandler(e){this._catchHandler=x(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new h("unregister-route-but-not-found-with-method",{method:e.method});const t=this._routes.get(e.method).indexOf(e);if(t>-1)this._routes.get(e.method).splice(t,1);else throw new h("unregister-route-route-not-registered")}}let w;const ue=()=>(w||(w=new he,w.addFetchListener(),w.addCacheListener()),w);function q(s,e,t){let n;if(typeof s=="string"){const r=new URL(s,location.href),i=({url:c})=>c.href===r.href;n=new R(i,e,t)}else if(s instanceof RegExp)n=new le(s,e,t);else if(typeof s=="function")n=new R(s,e,t);else if(s instanceof R)n=s;else throw new h("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});return ue().registerRoute(n),n}function de(s,e=[]){for(const t of[...s.searchParams.keys()])e.some(n=>n.test(t))&&s.searchParams.delete(t);return s}function*fe(s,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:t="index.html",cleanURLs:n=!0,urlManipulation:a}={}){const r=new URL(s,location.href);r.hash="",yield r.href;const i=de(r,e);if(yield i.href,t&&i.pathname.endsWith("/")){const c=new URL(i.href);c.pathname+=t,yield c.href}if(n){const c=new URL(i.href);c.pathname+=".html",yield c.href}if(a){const c=a({url:r});for(const o of c)yield o.href}}class pe extends R{constructor(e,t){const n=({request:a})=>{const r=e.getURLsToCacheKeys();for(const i of fe(a.url,t)){const c=r.get(i);if(c){const o=e.getIntegrityForCacheKey(c);return{cacheKey:c,integrity:o}}}};super(n,e.strategy)}}function ge(s){const e=j(),t=new pe(e,s);q(t)}const me="-precache-",we=async(s,e=me)=>{const n=(await self.caches.keys()).filter(a=>a.includes(e)&&a.includes(self.registration.scope)&&a!==s);return await Promise.all(n.map(a=>self.caches.delete(a))),n};function ye(){self.addEventListener("activate",(s=>{const e=b.getPrecacheName();s.waitUntil(we(e).then(t=>{}))}))}function _e(s){j().precache(s)}function Re(s,e){_e(s),ge(e)}class be extends W{async _handle(e,t){let n=await t.cacheMatch(e),a;if(!n)try{n=await t.fetchAndCachePut(e)}catch(r){r instanceof Error&&(a=r)}if(!n)throw new h("no-response",{url:e.url,error:a});return n}}function H(s){s.then(()=>{})}const Ce=(s,e)=>e.some(t=>s instanceof t);let A,K;function xe(){return A||(A=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])}function Ee(){return K||(K=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])}const V=new WeakMap,k=new WeakMap,$=new WeakMap,D=new WeakMap,v=new WeakMap;function Le(s){const e=new Promise((t,n)=>{const a=()=>{s.removeEventListener("success",r),s.removeEventListener("error",i)},r=()=>{t(f(s.result)),a()},i=()=>{n(s.error),a()};s.addEventListener("success",r),s.addEventListener("error",i)});return e.then(t=>{t instanceof IDBCursor&&V.set(t,s)}).catch(()=>{}),v.set(e,s),e}function De(s){if(k.has(s))return;const e=new Promise((t,n)=>{const a=()=>{s.removeEventListener("complete",r),s.removeEventListener("error",i),s.removeEventListener("abort",i)},r=()=>{t(),a()},i=()=>{n(s.error||new DOMException("AbortError","AbortError")),a()};s.addEventListener("complete",r),s.addEventListener("error",i),s.addEventListener("abort",i)});k.set(s,e)}let P={get(s,e,t){if(s instanceof IDBTransaction){if(e==="done")return k.get(s);if(e==="objectStoreNames")return s.objectStoreNames||$.get(s);if(e==="store")return t.objectStoreNames[1]?void 0:t.objectStore(t.objectStoreNames[0])}return f(s[e])},set(s,e,t){return s[e]=t,!0},has(s,e){return s instanceof IDBTransaction&&(e==="done"||e==="store")?!0:e in s}};function Ue(s){P=s(P)}function Te(s){return s===IDBDatabase.prototype.transaction&&!("objectStoreNames"in IDBTransaction.prototype)?function(e,...t){const n=s.call(U(this),e,...t);return $.set(n,e.sort?e.sort():[e]),f(n)}:Ee().includes(s)?function(...e){return s.apply(U(this),e),f(V.get(this))}:function(...e){return f(s.apply(U(this),e))}}function ke(s){return typeof s=="function"?Te(s):(s instanceof IDBTransaction&&De(s),Ce(s,xe())?new Proxy(s,P):s)}function f(s){if(s instanceof IDBRequest)return Le(s);if(D.has(s))return D.get(s);const e=ke(s);return e!==s&&(D.set(s,e),v.set(e,s)),e}const U=s=>v.get(s);function Pe(s,e,{blocked:t,upgrade:n,blocking:a,terminated:r}={}){const i=indexedDB.open(s,e),c=f(i);return n&&i.addEventListener("upgradeneeded",o=>{n(f(i.result),o.oldVersion,o.newVersion,f(i.transaction),o)}),t&&i.addEventListener("blocked",o=>t(o.oldVersion,o.newVersion,o)),c.then(o=>{r&&o.addEventListener("close",()=>r()),a&&o.addEventListener("versionchange",l=>a(l.oldVersion,l.newVersion,l))}).catch(()=>{}),c}function ve(s,{blocked:e}={}){const t=indexedDB.deleteDatabase(s);return e&&t.addEventListener("blocked",n=>e(n.oldVersion,n)),f(t).then(()=>{})}const Ie=["get","getKey","getAll","getAllKeys","count"],Ne=["put","add","delete","clear"],T=new Map;function S(s,e){if(!(s instanceof IDBDatabase&&!(e in s)&&typeof e=="string"))return;if(T.get(e))return T.get(e);const t=e.replace(/FromIndex$/,""),n=e!==t,a=Ne.includes(t);if(!(t in(n?IDBIndex:IDBObjectStore).prototype)||!(a||Ie.includes(t)))return;const r=async function(i,...c){const o=this.transaction(i,a?"readwrite":"readonly");let l=o.store;return n&&(l=l.index(c.shift())),(await Promise.all([l[t](...c),a&&o.done]))[0]};return T.set(e,r),r}Ue(s=>({...s,get:(e,t,n)=>S(e,t)||s.get(e,t,n),has:(e,t)=>!!S(e,t)||s.has(e,t)}));try{self["workbox:expiration:7.3.0"]&&_()}catch{}const Me="workbox-expiration",y="cache-entries",O=s=>{const e=new URL(s,location.href);return e.hash="",e.href};class Ae{constructor(e){this._db=null,this._cacheName=e}_upgradeDb(e){const t=e.createObjectStore(y,{keyPath:"id"});t.createIndex("cacheName","cacheName",{unique:!1}),t.createIndex("timestamp","timestamp",{unique:!1})}_upgradeDbAndDeleteOldDbs(e){this._upgradeDb(e),this._cacheName&&ve(this._cacheName)}async setTimestamp(e,t){e=O(e);const n={url:e,timestamp:t,cacheName:this._cacheName,id:this._getId(e)},r=(await this.getDb()).transaction(y,"readwrite",{durability:"relaxed"});await r.store.put(n),await r.done}async getTimestamp(e){const n=await(await this.getDb()).get(y,this._getId(e));return n==null?void 0:n.timestamp}async expireEntries(e,t){const n=await this.getDb();let a=await n.transaction(y).store.index("timestamp").openCursor(null,"prev");const r=[];let i=0;for(;a;){const o=a.value;o.cacheName===this._cacheName&&(e&&o.timestamp<e||t&&i>=t?r.push(a.value):i++),a=await a.continue()}const c=[];for(const o of r)await n.delete(y,o.id),c.push(o.url);return c}_getId(e){return this._cacheName+"|"+O(e)}async getDb(){return this._db||(this._db=await Pe(Me,1,{upgrade:this._upgradeDbAndDeleteOldDbs.bind(this)})),this._db}}class Ke{constructor(e,t={}){this._isRunning=!1,this._rerunRequested=!1,this._maxEntries=t.maxEntries,this._maxAgeSeconds=t.maxAgeSeconds,this._matchOptions=t.matchOptions,this._cacheName=e,this._timestampModel=new Ae(e)}async expireEntries(){if(this._isRunning){this._rerunRequested=!0;return}this._isRunning=!0;const e=this._maxAgeSeconds?Date.now()-this._maxAgeSeconds*1e3:0,t=await this._timestampModel.expireEntries(e,this._maxEntries),n=await self.caches.open(this._cacheName);for(const a of t)await n.delete(a,this._matchOptions);this._isRunning=!1,this._rerunRequested&&(this._rerunRequested=!1,H(this.expireEntries()))}async updateTimestamp(e){await this._timestampModel.setTimestamp(e,Date.now())}async isURLExpired(e){if(this._maxAgeSeconds){const t=await this._timestampModel.getTimestamp(e),n=Date.now()-this._maxAgeSeconds*1e3;return t!==void 0?t<n:!0}else return!1}async delete(){this._rerunRequested=!1,await this._timestampModel.expireEntries(1/0)}}function Se(s){B.add(s)}class Oe{constructor(e={}){this.cachedResponseWillBeUsed=async({event:t,request:n,cacheName:a,cachedResponse:r})=>{if(!r)return null;const i=this._isResponseDateFresh(r),c=this._getCacheExpiration(a);H(c.expireEntries());const o=c.updateTimestamp(n.url);if(t)try{t.waitUntil(o)}catch{}return i?r:null},this.cacheDidUpdate=async({cacheName:t,request:n})=>{const a=this._getCacheExpiration(t);await a.updateTimestamp(n.url),await a.expireEntries()},this._config=e,this._maxAgeSeconds=e.maxAgeSeconds,this._cacheExpirations=new Map,e.purgeOnQuotaError&&Se(()=>this.deleteCacheAndMetadata())}_getCacheExpiration(e){if(e===b.getRuntimeName())throw new h("expire-custom-caches-only");let t=this._cacheExpirations.get(e);return t||(t=new Ke(e,this._config),this._cacheExpirations.set(e,t)),t}_isResponseDateFresh(e){if(!this._maxAgeSeconds)return!0;const t=this._getDateHeaderTimestamp(e);if(t===null)return!0;const n=Date.now();return t>=n-this._maxAgeSeconds*1e3}_getDateHeaderTimestamp(e){if(!e.headers.has("date"))return null;const t=e.headers.get("date"),a=new Date(t).getTime();return isNaN(a)?null:a}async deleteCacheAndMetadata(){for(const[e,t]of this._cacheExpirations)await self.caches.delete(e),await t.delete();this._cacheExpirations=new Map}}Re([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"0f93805414c783a30b72e0ce88f2c7c4","url":"icons/icon.svg"},{"revision":"5dee5ddcd8e8533edb348118334d9756","url":"icons/icon-512.png"},{"revision":"75734e6b38a556148f51b9e10eeb01c8","url":"icons/icon-192.png"},{"revision":"0362e0eb00358646fd4c97674945adba","url":"icons/icon-180.png"},{"revision":null,"url":"assets/xychartDiagram-JWTSCODW-D1U0PBps.js"},{"revision":null,"url":"assets/vennDiagram-LZ73GAT5-CQy8NUxW.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-BwGtQefY.js"},{"revision":null,"url":"assets/timeline-definition-YZTLITO2-AB47RPpS.js"},{"revision":null,"url":"assets/stateDiagram-v2-FVOUBMTO-Dr2a5PWq.js"},{"revision":null,"url":"assets/stateDiagram-RAJIS63D-DBbQtnkh.js"},{"revision":null,"url":"assets/sequenceDiagram-2WXFIKYE-CCATgMDC.js"},{"revision":null,"url":"assets/sankeyDiagram-WA2Y5GQK-DqRGFuVJ.js"},{"revision":null,"url":"assets/requirementDiagram-Z7DCOOCP-DzYp2J9t.js"},{"revision":null,"url":"assets/quadrantDiagram-337W2JSQ-DBgEkZee.js"},{"revision":null,"url":"assets/pieDiagram-SKSYHLDU-Db_hnpTO.js"},{"revision":null,"url":"assets/ordinal-Cboi1Yqb.js"},{"revision":null,"url":"assets/mindmap-definition-YRQLILUH-KXwvxrd9.js"},{"revision":null,"url":"assets/linear-pPVtYfoA.js"},{"revision":null,"url":"assets/layout-C4hgRWBc.js"},{"revision":null,"url":"assets/katex-B1X10hvy.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-DlsqM5ac.js"},{"revision":null,"url":"assets/journeyDiagram-4ABVD52K-DOKjshE4.js"},{"revision":null,"url":"assets/ishikawaDiagram-PHBUUO56-BTx9nUR_.js"},{"revision":null,"url":"assets/init-Gi6I4Gst.js"},{"revision":null,"url":"assets/infoDiagram-LFFYTUFH-B50sX0Jk.js"},{"revision":null,"url":"assets/index-pqtccC7s.js"},{"revision":null,"url":"assets/index-7DPrKRHX.css"},{"revision":null,"url":"assets/graph-CaPDDY3I.js"},{"revision":null,"url":"assets/gitGraphDiagram-K3NZZRJ6-CZ0c5437.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-BRH4oYpz.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-7__LLCFp.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-xb7jd7iV.js"},{"revision":null,"url":"assets/diagram-P4PSJMXO-Cl1dGq__.js"},{"revision":null,"url":"assets/diagram-IFDJBPK2-B7r-HJa0.js"},{"revision":null,"url":"assets/diagram-E7M64L7V-yhW3nXxA.js"},{"revision":null,"url":"assets/defaultLocale-DX6XiGOO.js"},{"revision":null,"url":"assets/dagre-KLK3FWXG-BOfJIpm3.js"},{"revision":null,"url":"assets/cytoscape.esm-BQaXIfA_.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-CTeXZoSq.js"},{"revision":null,"url":"assets/clone-BQhUsBH5.js"},{"revision":null,"url":"assets/classDiagram-v2-RAHNMMFH-CwKQYDdP.js"},{"revision":null,"url":"assets/classDiagram-VBA2DB6C-CwKQYDdP.js"},{"revision":null,"url":"assets/chunk-WL4C6EOR-DY15q7Tk.js"},{"revision":null,"url":"assets/chunk-QZHKN3VN-DDY6gqIZ.js"},{"revision":null,"url":"assets/chunk-NQ4KR5QH-BP6XJFdX.js"},{"revision":null,"url":"assets/chunk-KX2RTZJC-BZlXzthI.js"},{"revision":null,"url":"assets/chunk-JSJVCQXG-CudZY5_F.js"},{"revision":null,"url":"assets/chunk-FMBD7UC4-cK52FAx0.js"},{"revision":null,"url":"assets/chunk-55IACEB6-CRSrEoDB.js"},{"revision":null,"url":"assets/chunk-4BX2VUAB-eU5lnLp-.js"},{"revision":null,"url":"assets/channel-spGqRIlf.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-CPV76ZUM.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-Dh31wJRm.js"},{"revision":null,"url":"assets/architectureDiagram-2XIMDMQ5-BFCoYW28.js"},{"revision":null,"url":"assets/arc-BBjpe_hN.js"},{"revision":null,"url":"assets/_baseUniq-CmudMx6k.js"},{"revision":null,"url":"assets/_basePickBy-BpcK6jhC.js"},{"revision":"0362e0eb00358646fd4c97674945adba","url":"icons/icon-180.png"},{"revision":"75734e6b38a556148f51b9e10eeb01c8","url":"icons/icon-192.png"},{"revision":"5dee5ddcd8e8533edb348118334d9756","url":"icons/icon-512.png"},{"revision":"b0747e8d6cde0d45e05be8e5c731729e","url":"manifest.webmanifest"}]);ye();q(({url:s})=>s.hostname==="cdn.jsdelivr.net"&&s.pathname.endsWith(".ttf"),new be({cacheName:"termbeam-fonts",plugins:[new Oe({maxEntries:5,maxAgeSeconds:365*24*60*60})]}));self.addEventListener("message",s=>{var e;((e=s.data)==null?void 0:e.type)==="CLEAR_CACHES"&&caches.keys().then(t=>{for(const n of t)n!=="workbox-precache-v2"&&caches.delete(n)})});self.addEventListener("install",()=>{self.skipWaiting()});self.addEventListener("activate",s=>{s.waitUntil(caches.delete("termbeam-navigation").then(()=>self.clients.claim()))});self.addEventListener("push",s=>{let e={title:"Command finished",body:"TermBeam"};if(s.data)try{e=s.data.json()}catch{}s.waitUntil(self.clients.matchAll({type:"window",includeUncontrolled:!0}).then(async t=>{if(t.some(r=>r.url.includes(self.location.origin)&&r.focused))return;const a={body:e.body||"A command has completed",icon:"/icons/icon-192.png",badge:"/icons/icon-192.png",tag:"termbeam-cmd",renotify:!0,data:{url:"/"},vibrate:[200,100,200]};try{await self.navigator.setAppBadge(1)}catch{}return self.registration.showNotification(e.title||"Command finished",a)}))});self.addEventListener("notificationclick",s=>{var t;s.notification.close();try{self.navigator.clearAppBadge()}catch{}const e=((t=s.notification.data)==null?void 0:t.url)||"/";s.waitUntil(self.clients.matchAll({type:"window",includeUncontrolled:!0}).then(n=>{for(const a of n)if(a.url.includes(self.location.origin)&&"focus"in a)return a.focus();return self.clients.openWindow(e)}))});
2
+ This is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(c)}}}install(e){return N(e,async()=>{const t=new Y;this.strategy.plugins.push(t);for(const[r,i]of this._urlsToCacheKeys){const c=this._cacheKeysToIntegrities.get(i),o=this._urlsToCacheModes.get(r),l=new Request(r,{integrity:c,cache:o,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:i},request:l,event:e}))}const{updatedURLs:n,notUpdatedURLs:a}=t;return{updatedURLs:n,notUpdatedURLs:a}})}activate(e){return N(e,async()=>{const t=await self.caches.open(this.strategy.cacheName),n=await t.keys(),a=new Set(this._urlsToCacheKeys.values()),r=[];for(const i of n)a.has(i.url)||(await t.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){const t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){const t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){const t=this.getCacheKeyForURL(e);if(!t)throw new h("non-precached-url",{url:e});return n=>(n.request=new Request(e),n.params=Object.assign({cacheKey:t},n.params),this.strategy.handle(n))}}let L;const j=()=>(L||(L=new oe),L);try{self["workbox:routing:7.3.0"]&&_()}catch{}const F="GET",x=s=>s&&typeof s=="object"?s:{handle:s};class R{constructor(e,t,n=F){this.handler=x(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=x(e)}}class le extends R{constructor(e,t,n){const a=({url:r})=>{const i=e.exec(r.href);if(i&&!(r.origin!==location.origin&&i.index!==0))return i.slice(1)};super(a,t,n)}}class he{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",(e=>{const{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener("message",(e=>{if(e.data&&e.data.type==="CACHE_URLS"){const{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(a=>{typeof a=="string"&&(a=[a]);const r=new Request(...a);return this.handleRequest({request:r,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){const n=new URL(e.url,location.href);if(!n.protocol.startsWith("http"))return;const a=n.origin===location.origin,{params:r,route:i}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:n});let c=i&&i.handler;const o=e.method;if(!c&&this._defaultHandlerMap.has(o)&&(c=this._defaultHandlerMap.get(o)),!c)return;let l;try{l=c.handle({url:n,request:e,event:t,params:r})}catch(u){l=Promise.reject(u)}const g=i&&i.catchHandler;return l instanceof Promise&&(this._catchHandler||g)&&(l=l.catch(async u=>{if(g)try{return await g.handle({url:n,request:e,event:t,params:r})}catch(I){I instanceof Error&&(u=I)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw u})),l}findMatchingRoute({url:e,sameOrigin:t,request:n,event:a}){const r=this._routes.get(n.method)||[];for(const i of r){let c;const o=i.match({url:e,sameOrigin:t,request:n,event:a});if(o)return c=o,(Array.isArray(c)&&c.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o=="boolean")&&(c=void 0),{route:i,params:c}}return{}}setDefaultHandler(e,t=F){this._defaultHandlerMap.set(t,x(e))}setCatchHandler(e){this._catchHandler=x(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new h("unregister-route-but-not-found-with-method",{method:e.method});const t=this._routes.get(e.method).indexOf(e);if(t>-1)this._routes.get(e.method).splice(t,1);else throw new h("unregister-route-route-not-registered")}}let w;const ue=()=>(w||(w=new he,w.addFetchListener(),w.addCacheListener()),w);function q(s,e,t){let n;if(typeof s=="string"){const r=new URL(s,location.href),i=({url:c})=>c.href===r.href;n=new R(i,e,t)}else if(s instanceof RegExp)n=new le(s,e,t);else if(typeof s=="function")n=new R(s,e,t);else if(s instanceof R)n=s;else throw new h("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});return ue().registerRoute(n),n}function de(s,e=[]){for(const t of[...s.searchParams.keys()])e.some(n=>n.test(t))&&s.searchParams.delete(t);return s}function*fe(s,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:t="index.html",cleanURLs:n=!0,urlManipulation:a}={}){const r=new URL(s,location.href);r.hash="",yield r.href;const i=de(r,e);if(yield i.href,t&&i.pathname.endsWith("/")){const c=new URL(i.href);c.pathname+=t,yield c.href}if(n){const c=new URL(i.href);c.pathname+=".html",yield c.href}if(a){const c=a({url:r});for(const o of c)yield o.href}}class pe extends R{constructor(e,t){const n=({request:a})=>{const r=e.getURLsToCacheKeys();for(const i of fe(a.url,t)){const c=r.get(i);if(c){const o=e.getIntegrityForCacheKey(c);return{cacheKey:c,integrity:o}}}};super(n,e.strategy)}}function ge(s){const e=j(),t=new pe(e,s);q(t)}const me="-precache-",we=async(s,e=me)=>{const n=(await self.caches.keys()).filter(a=>a.includes(e)&&a.includes(self.registration.scope)&&a!==s);return await Promise.all(n.map(a=>self.caches.delete(a))),n};function ye(){self.addEventListener("activate",(s=>{const e=b.getPrecacheName();s.waitUntil(we(e).then(t=>{}))}))}function _e(s){j().precache(s)}function Re(s,e){_e(s),ge(e)}class be extends W{async _handle(e,t){let n=await t.cacheMatch(e),a;if(!n)try{n=await t.fetchAndCachePut(e)}catch(r){r instanceof Error&&(a=r)}if(!n)throw new h("no-response",{url:e.url,error:a});return n}}function H(s){s.then(()=>{})}const Ce=(s,e)=>e.some(t=>s instanceof t);let A,K;function xe(){return A||(A=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])}function Ee(){return K||(K=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])}const V=new WeakMap,k=new WeakMap,$=new WeakMap,D=new WeakMap,v=new WeakMap;function Le(s){const e=new Promise((t,n)=>{const a=()=>{s.removeEventListener("success",r),s.removeEventListener("error",i)},r=()=>{t(f(s.result)),a()},i=()=>{n(s.error),a()};s.addEventListener("success",r),s.addEventListener("error",i)});return e.then(t=>{t instanceof IDBCursor&&V.set(t,s)}).catch(()=>{}),v.set(e,s),e}function De(s){if(k.has(s))return;const e=new Promise((t,n)=>{const a=()=>{s.removeEventListener("complete",r),s.removeEventListener("error",i),s.removeEventListener("abort",i)},r=()=>{t(),a()},i=()=>{n(s.error||new DOMException("AbortError","AbortError")),a()};s.addEventListener("complete",r),s.addEventListener("error",i),s.addEventListener("abort",i)});k.set(s,e)}let P={get(s,e,t){if(s instanceof IDBTransaction){if(e==="done")return k.get(s);if(e==="objectStoreNames")return s.objectStoreNames||$.get(s);if(e==="store")return t.objectStoreNames[1]?void 0:t.objectStore(t.objectStoreNames[0])}return f(s[e])},set(s,e,t){return s[e]=t,!0},has(s,e){return s instanceof IDBTransaction&&(e==="done"||e==="store")?!0:e in s}};function Ue(s){P=s(P)}function Te(s){return s===IDBDatabase.prototype.transaction&&!("objectStoreNames"in IDBTransaction.prototype)?function(e,...t){const n=s.call(U(this),e,...t);return $.set(n,e.sort?e.sort():[e]),f(n)}:Ee().includes(s)?function(...e){return s.apply(U(this),e),f(V.get(this))}:function(...e){return f(s.apply(U(this),e))}}function ke(s){return typeof s=="function"?Te(s):(s instanceof IDBTransaction&&De(s),Ce(s,xe())?new Proxy(s,P):s)}function f(s){if(s instanceof IDBRequest)return Le(s);if(D.has(s))return D.get(s);const e=ke(s);return e!==s&&(D.set(s,e),v.set(e,s)),e}const U=s=>v.get(s);function Pe(s,e,{blocked:t,upgrade:n,blocking:a,terminated:r}={}){const i=indexedDB.open(s,e),c=f(i);return n&&i.addEventListener("upgradeneeded",o=>{n(f(i.result),o.oldVersion,o.newVersion,f(i.transaction),o)}),t&&i.addEventListener("blocked",o=>t(o.oldVersion,o.newVersion,o)),c.then(o=>{r&&o.addEventListener("close",()=>r()),a&&o.addEventListener("versionchange",l=>a(l.oldVersion,l.newVersion,l))}).catch(()=>{}),c}function ve(s,{blocked:e}={}){const t=indexedDB.deleteDatabase(s);return e&&t.addEventListener("blocked",n=>e(n.oldVersion,n)),f(t).then(()=>{})}const Ie=["get","getKey","getAll","getAllKeys","count"],Ne=["put","add","delete","clear"],T=new Map;function S(s,e){if(!(s instanceof IDBDatabase&&!(e in s)&&typeof e=="string"))return;if(T.get(e))return T.get(e);const t=e.replace(/FromIndex$/,""),n=e!==t,a=Ne.includes(t);if(!(t in(n?IDBIndex:IDBObjectStore).prototype)||!(a||Ie.includes(t)))return;const r=async function(i,...c){const o=this.transaction(i,a?"readwrite":"readonly");let l=o.store;return n&&(l=l.index(c.shift())),(await Promise.all([l[t](...c),a&&o.done]))[0]};return T.set(e,r),r}Ue(s=>({...s,get:(e,t,n)=>S(e,t)||s.get(e,t,n),has:(e,t)=>!!S(e,t)||s.has(e,t)}));try{self["workbox:expiration:7.3.0"]&&_()}catch{}const Me="workbox-expiration",y="cache-entries",O=s=>{const e=new URL(s,location.href);return e.hash="",e.href};class Ae{constructor(e){this._db=null,this._cacheName=e}_upgradeDb(e){const t=e.createObjectStore(y,{keyPath:"id"});t.createIndex("cacheName","cacheName",{unique:!1}),t.createIndex("timestamp","timestamp",{unique:!1})}_upgradeDbAndDeleteOldDbs(e){this._upgradeDb(e),this._cacheName&&ve(this._cacheName)}async setTimestamp(e,t){e=O(e);const n={url:e,timestamp:t,cacheName:this._cacheName,id:this._getId(e)},r=(await this.getDb()).transaction(y,"readwrite",{durability:"relaxed"});await r.store.put(n),await r.done}async getTimestamp(e){const n=await(await this.getDb()).get(y,this._getId(e));return n==null?void 0:n.timestamp}async expireEntries(e,t){const n=await this.getDb();let a=await n.transaction(y).store.index("timestamp").openCursor(null,"prev");const r=[];let i=0;for(;a;){const o=a.value;o.cacheName===this._cacheName&&(e&&o.timestamp<e||t&&i>=t?r.push(a.value):i++),a=await a.continue()}const c=[];for(const o of r)await n.delete(y,o.id),c.push(o.url);return c}_getId(e){return this._cacheName+"|"+O(e)}async getDb(){return this._db||(this._db=await Pe(Me,1,{upgrade:this._upgradeDbAndDeleteOldDbs.bind(this)})),this._db}}class Ke{constructor(e,t={}){this._isRunning=!1,this._rerunRequested=!1,this._maxEntries=t.maxEntries,this._maxAgeSeconds=t.maxAgeSeconds,this._matchOptions=t.matchOptions,this._cacheName=e,this._timestampModel=new Ae(e)}async expireEntries(){if(this._isRunning){this._rerunRequested=!0;return}this._isRunning=!0;const e=this._maxAgeSeconds?Date.now()-this._maxAgeSeconds*1e3:0,t=await this._timestampModel.expireEntries(e,this._maxEntries),n=await self.caches.open(this._cacheName);for(const a of t)await n.delete(a,this._matchOptions);this._isRunning=!1,this._rerunRequested&&(this._rerunRequested=!1,H(this.expireEntries()))}async updateTimestamp(e){await this._timestampModel.setTimestamp(e,Date.now())}async isURLExpired(e){if(this._maxAgeSeconds){const t=await this._timestampModel.getTimestamp(e),n=Date.now()-this._maxAgeSeconds*1e3;return t!==void 0?t<n:!0}else return!1}async delete(){this._rerunRequested=!1,await this._timestampModel.expireEntries(1/0)}}function Se(s){B.add(s)}class Oe{constructor(e={}){this.cachedResponseWillBeUsed=async({event:t,request:n,cacheName:a,cachedResponse:r})=>{if(!r)return null;const i=this._isResponseDateFresh(r),c=this._getCacheExpiration(a);H(c.expireEntries());const o=c.updateTimestamp(n.url);if(t)try{t.waitUntil(o)}catch{}return i?r:null},this.cacheDidUpdate=async({cacheName:t,request:n})=>{const a=this._getCacheExpiration(t);await a.updateTimestamp(n.url),await a.expireEntries()},this._config=e,this._maxAgeSeconds=e.maxAgeSeconds,this._cacheExpirations=new Map,e.purgeOnQuotaError&&Se(()=>this.deleteCacheAndMetadata())}_getCacheExpiration(e){if(e===b.getRuntimeName())throw new h("expire-custom-caches-only");let t=this._cacheExpirations.get(e);return t||(t=new Ke(e,this._config),this._cacheExpirations.set(e,t)),t}_isResponseDateFresh(e){if(!this._maxAgeSeconds)return!0;const t=this._getDateHeaderTimestamp(e);if(t===null)return!0;const n=Date.now();return t>=n-this._maxAgeSeconds*1e3}_getDateHeaderTimestamp(e){if(!e.headers.has("date"))return null;const t=e.headers.get("date"),a=new Date(t).getTime();return isNaN(a)?null:a}async deleteCacheAndMetadata(){for(const[e,t]of this._cacheExpirations)await self.caches.delete(e),await t.delete();this._cacheExpirations=new Map}}Re([{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},{"revision":"0f93805414c783a30b72e0ce88f2c7c4","url":"icons/icon.svg"},{"revision":"5dee5ddcd8e8533edb348118334d9756","url":"icons/icon-512.png"},{"revision":"75734e6b38a556148f51b9e10eeb01c8","url":"icons/icon-192.png"},{"revision":"0362e0eb00358646fd4c97674945adba","url":"icons/icon-180.png"},{"revision":null,"url":"assets/xychartDiagram-JWTSCODW-Dn4p5BUd.js"},{"revision":null,"url":"assets/vennDiagram-LZ73GAT5-Ztcsx3HA.js"},{"revision":null,"url":"assets/treemap-KZPCXAKY-FdKKPGme.js"},{"revision":null,"url":"assets/timeline-definition-YZTLITO2-C1TqIxxb.js"},{"revision":null,"url":"assets/stateDiagram-v2-FVOUBMTO-oq90yqVz.js"},{"revision":null,"url":"assets/stateDiagram-RAJIS63D-DBaX5xL4.js"},{"revision":null,"url":"assets/sequenceDiagram-2WXFIKYE-Cd4PXvbK.js"},{"revision":null,"url":"assets/sankeyDiagram-WA2Y5GQK-BRHTtm5o.js"},{"revision":null,"url":"assets/requirementDiagram-Z7DCOOCP-kGDKpJ88.js"},{"revision":null,"url":"assets/quadrantDiagram-337W2JSQ-v7ZVRO3r.js"},{"revision":null,"url":"assets/pieDiagram-SKSYHLDU-DjBXbSpO.js"},{"revision":null,"url":"assets/ordinal-Cboi1Yqb.js"},{"revision":null,"url":"assets/mindmap-definition-YRQLILUH-1Tw3mDSx.js"},{"revision":null,"url":"assets/linear-CAYODrs8.js"},{"revision":null,"url":"assets/layout-DJKj_FTS.js"},{"revision":null,"url":"assets/katex-B1X10hvy.js"},{"revision":null,"url":"assets/kanban-definition-K7BYSVSG-Cfjl6s7S.js"},{"revision":null,"url":"assets/journeyDiagram-4ABVD52K-Dwd7nrwc.js"},{"revision":null,"url":"assets/ishikawaDiagram-PHBUUO56-ax9eusTy.js"},{"revision":null,"url":"assets/init-Gi6I4Gst.js"},{"revision":null,"url":"assets/infoDiagram-LFFYTUFH-B2kINdu2.js"},{"revision":null,"url":"assets/index-krC-nFgj.js"},{"revision":null,"url":"assets/index-OLhvO-lo.css"},{"revision":null,"url":"assets/graph-RqkgQOtG.js"},{"revision":null,"url":"assets/gitGraphDiagram-K3NZZRJ6-CqevZOIa.js"},{"revision":null,"url":"assets/ganttDiagram-A5KZAMGK-CWqdZ7OI.js"},{"revision":null,"url":"assets/flowDiagram-PKNHOUZH-Boz3lacJ.js"},{"revision":null,"url":"assets/erDiagram-INFDFZHY-wCvCuo-B.js"},{"revision":null,"url":"assets/diagram-P4PSJMXO-CU7V3fXy.js"},{"revision":null,"url":"assets/diagram-IFDJBPK2-CLQVFUVj.js"},{"revision":null,"url":"assets/diagram-E7M64L7V-2MENMB7x.js"},{"revision":null,"url":"assets/defaultLocale-DX6XiGOO.js"},{"revision":null,"url":"assets/dagre-KLK3FWXG-BMtFOQy3.js"},{"revision":null,"url":"assets/cytoscape.esm-BQaXIfA_.js"},{"revision":null,"url":"assets/cose-bilkent-S5V4N54A-DUAC9S22.js"},{"revision":null,"url":"assets/clone-Crb49TJI.js"},{"revision":null,"url":"assets/classDiagram-v2-RAHNMMFH-CcqrO3eb.js"},{"revision":null,"url":"assets/classDiagram-VBA2DB6C-CcqrO3eb.js"},{"revision":null,"url":"assets/chunk-WL4C6EOR-BjZnqD0U.js"},{"revision":null,"url":"assets/chunk-QZHKN3VN-BhaEnvkv.js"},{"revision":null,"url":"assets/chunk-NQ4KR5QH-Bg0iNBVP.js"},{"revision":null,"url":"assets/chunk-KX2RTZJC-rUuzVVLE.js"},{"revision":null,"url":"assets/chunk-JSJVCQXG-vfzfWdiO.js"},{"revision":null,"url":"assets/chunk-FMBD7UC4-v0DR1X_4.js"},{"revision":null,"url":"assets/chunk-55IACEB6-DJVrjvbz.js"},{"revision":null,"url":"assets/chunk-4BX2VUAB-4yc1d8Nd.js"},{"revision":null,"url":"assets/channel-CLKml9tB.js"},{"revision":null,"url":"assets/c4Diagram-IC4MRINW-3ppw40cY.js"},{"revision":null,"url":"assets/blockDiagram-WCTKOSBZ-CfD0B0tq.js"},{"revision":null,"url":"assets/architectureDiagram-2XIMDMQ5-0LiO_Haj.js"},{"revision":null,"url":"assets/arc-Dzz7iV1B.js"},{"revision":null,"url":"assets/_baseUniq-ClnVVws1.js"},{"revision":null,"url":"assets/_basePickBy-0kpFmj0i.js"},{"revision":"0362e0eb00358646fd4c97674945adba","url":"icons/icon-180.png"},{"revision":"75734e6b38a556148f51b9e10eeb01c8","url":"icons/icon-192.png"},{"revision":"5dee5ddcd8e8533edb348118334d9756","url":"icons/icon-512.png"},{"revision":"b0747e8d6cde0d45e05be8e5c731729e","url":"manifest.webmanifest"}]);ye();q(({url:s})=>s.hostname==="cdn.jsdelivr.net"&&s.pathname.endsWith(".ttf"),new be({cacheName:"termbeam-fonts",plugins:[new Oe({maxEntries:5,maxAgeSeconds:365*24*60*60})]}));self.addEventListener("message",s=>{var e;((e=s.data)==null?void 0:e.type)==="CLEAR_CACHES"&&caches.keys().then(t=>{for(const n of t)n!=="workbox-precache-v2"&&caches.delete(n)})});self.addEventListener("install",()=>{self.skipWaiting()});self.addEventListener("activate",s=>{s.waitUntil(caches.delete("termbeam-navigation").then(()=>self.clients.claim()))});self.addEventListener("push",s=>{let e={title:"Command finished",body:"TermBeam"};if(s.data)try{e=s.data.json()}catch{}s.waitUntil(self.clients.matchAll({type:"window",includeUncontrolled:!0}).then(async t=>{if(t.some(r=>r.url.includes(self.location.origin)&&r.focused))return;const a={body:e.body||"A command has completed",icon:"/icons/icon-192.png",badge:"/icons/icon-192.png",tag:"termbeam-cmd",renotify:!0,data:{url:"/"},vibrate:[200,100,200]};try{await self.navigator.setAppBadge(1)}catch{}return self.registration.showNotification(e.title||"Command finished",a)}))});self.addEventListener("notificationclick",s=>{var t;s.notification.close();try{self.navigator.clearAppBadge()}catch{}const e=((t=s.notification.data)==null?void 0:t.url)||"/";s.waitUntil(self.clients.matchAll({type:"window",includeUncontrolled:!0}).then(n=>{for(const a of n)if(a.url.includes(self.location.origin)&&"focus"in a)return a.focus();return self.clients.openWindow(e)}))});
@@ -13,7 +13,7 @@ const { createAuth } = require('./auth');
13
13
  const { SessionManager } = require('./sessions');
14
14
  const { setupRoutes, cleanupUploadedFiles } = require('./routes');
15
15
  const { setupWebSocket } = require('./websocket');
16
- const { startTunnel, cleanupTunnel, findDevtunnel } = require('../tunnel');
16
+ const { startTunnel, cleanupTunnel, findDevtunnel, tunnelEvents } = require('../tunnel');
17
17
  const { createPreviewProxy } = require('./preview');
18
18
  const { writeConnectionConfig, removeConnectionConfig } = require('../cli/resume');
19
19
  const { checkForUpdate, detectInstallMethod } = require('../utils/update-check');
@@ -110,6 +110,7 @@ function createTermBeamServer(overrides = {}) {
110
110
  auth.cleanup();
111
111
  sessions.shutdown();
112
112
  cleanupUploadedFiles();
113
+ tunnelEvents.removeAllListeners();
113
114
  cleanupTunnel();
114
115
  removeConnectionConfig();
115
116
  for (const client of wss.clients) {
@@ -257,6 +258,22 @@ function createTermBeamServer(overrides = {}) {
257
258
  log.warn('Tunnel failed to start, falling back to LAN-only');
258
259
  console.log(' ⚠️ Tunnel failed to start. Using LAN only.');
259
260
  }
261
+
262
+ // Tunnel watchdog events
263
+ tunnelEvents.on('disconnected', () => {
264
+ log.warn('Tunnel disconnected — watchdog will attempt to reconnect');
265
+ });
266
+ tunnelEvents.on('reconnecting', ({ attempt, delay }) => {
267
+ log.info(`Tunnel reconnecting (attempt ${attempt}, backoff ${delay}ms)`);
268
+ });
269
+ tunnelEvents.on('connected', ({ url }) => {
270
+ log.info(`Tunnel connected: ${url}`);
271
+ });
272
+ tunnelEvents.on('failed', ({ attempts }) => {
273
+ log.error(
274
+ `Tunnel watchdog gave up after ${attempts} attempts — tunnel URL is unreachable`,
275
+ );
276
+ });
260
277
  }
261
278
 
262
279
  console.log(` Shell: ${config.shell}`);
@@ -1,7 +1,8 @@
1
- const { execSync, execFileSync, spawn } = require('child_process');
1
+ const { execSync, execFileSync, execFile, spawn } = require('child_process');
2
2
  const path = require('path');
3
3
  const fs = require('fs');
4
4
  const os = require('os');
5
+ const EventEmitter = require('events');
5
6
  const log = require('../utils/logger');
6
7
  const { promptInstall } = require('./install');
7
8
 
@@ -12,6 +13,19 @@ let tunnelId = null;
12
13
  let tunnelProc = null;
13
14
  let devtunnelCmd = 'devtunnel';
14
15
 
16
+ // --- Watchdog state ---
17
+ const tunnelEvents = new EventEmitter();
18
+ let healthCheckInterval = null;
19
+ let consecutiveFailures = 0;
20
+ let restartAttempts = 0;
21
+ let isRestarting = false;
22
+ let restartTimer = null;
23
+
24
+ const HEALTH_CHECK_INTERVAL = 30_000; // 30s between checks
25
+ const HEALTH_CHECK_GRACE = 2; // 2 consecutive failures before restart
26
+ const MAX_RESTART_ATTEMPTS = 10;
27
+ const BACKOFF_DELAYS = [1000, 2000, 5000, 10_000, 15_000, 30_000]; // then stays at 30s
28
+
15
29
  const SAFE_ID_RE = /^[a-zA-Z0-9._-]+$/;
16
30
 
17
31
  const DEVICE_CODE_INITIAL_TIMEOUT = 15000;
@@ -135,6 +149,203 @@ function isTunnelValid(id) {
135
149
 
136
150
  let isPersisted = false;
137
151
 
152
+ // --- Watchdog: health check & auto-restart ---
153
+
154
+ function checkTunnelHealth() {
155
+ if (!tunnelId || !tunnelProc || isRestarting) return;
156
+
157
+ const abortCtrl = new AbortController();
158
+ const timer = setTimeout(() => abortCtrl.abort(), 10_000);
159
+
160
+ execFile(
161
+ devtunnelCmd,
162
+ ['show', tunnelId],
163
+ { encoding: 'utf-8', signal: abortCtrl.signal },
164
+ (err, stdout) => {
165
+ clearTimeout(timer);
166
+
167
+ if (err) {
168
+ consecutiveFailures++;
169
+ log.warn(
170
+ `Tunnel health check error: ${err.message} (${consecutiveFailures}/${HEALTH_CHECK_GRACE})`,
171
+ );
172
+ if (consecutiveFailures >= HEALTH_CHECK_GRACE) {
173
+ handleTunnelFailure();
174
+ }
175
+ return;
176
+ }
177
+
178
+ const match = stdout.match(/Host connections\s*:\s*(\d+)/i);
179
+ if (!match) {
180
+ consecutiveFailures++;
181
+ log.warn(
182
+ `Tunnel health check: could not parse host connections (${consecutiveFailures}/${HEALTH_CHECK_GRACE})`,
183
+ );
184
+ if (consecutiveFailures >= HEALTH_CHECK_GRACE) {
185
+ handleTunnelFailure();
186
+ }
187
+ return;
188
+ }
189
+
190
+ const hostConns = parseInt(match[1], 10);
191
+ if (hostConns > 0) {
192
+ if (consecutiveFailures > 0) {
193
+ log.info(`Tunnel health restored (${hostConns} host connection(s))`);
194
+ }
195
+ consecutiveFailures = 0;
196
+ return;
197
+ }
198
+
199
+ consecutiveFailures++;
200
+ log.warn(
201
+ `Tunnel health check: 0 host connections (${consecutiveFailures}/${HEALTH_CHECK_GRACE})`,
202
+ );
203
+
204
+ if (consecutiveFailures >= HEALTH_CHECK_GRACE) {
205
+ log.warn('Tunnel connection lost — initiating restart');
206
+ handleTunnelFailure();
207
+ }
208
+ },
209
+ );
210
+ }
211
+
212
+ function startHealthCheck() {
213
+ stopHealthCheck();
214
+ consecutiveFailures = 0;
215
+ healthCheckInterval = setInterval(checkTunnelHealth, HEALTH_CHECK_INTERVAL);
216
+ healthCheckInterval.unref();
217
+ }
218
+
219
+ function stopHealthCheck() {
220
+ if (healthCheckInterval) {
221
+ clearInterval(healthCheckInterval);
222
+ healthCheckInterval = null;
223
+ }
224
+ }
225
+
226
+ function handleTunnelFailure() {
227
+ if (isRestarting) return;
228
+ stopHealthCheck();
229
+
230
+ // Kill the zombie process
231
+ if (tunnelProc) {
232
+ try {
233
+ if (process.platform === 'win32' && tunnelProc.pid) {
234
+ try {
235
+ execFileSync('taskkill', ['/pid', String(tunnelProc.pid), '/T', '/F'], {
236
+ stdio: 'pipe',
237
+ timeout: 5000,
238
+ });
239
+ } catch {
240
+ /* best effort */
241
+ }
242
+ } else {
243
+ tunnelProc.kill('SIGKILL');
244
+ }
245
+ } catch {
246
+ /* best effort */
247
+ }
248
+ tunnelProc = null;
249
+ }
250
+
251
+ tunnelEvents.emit('disconnected');
252
+ scheduleRestart();
253
+ }
254
+
255
+ function scheduleRestart() {
256
+ if (restartAttempts >= MAX_RESTART_ATTEMPTS) {
257
+ log.error(
258
+ `Tunnel restart failed after ${MAX_RESTART_ATTEMPTS} attempts — giving up. Tunnel URL is unreachable.`,
259
+ );
260
+ tunnelEvents.emit('failed', { attempts: restartAttempts });
261
+ isRestarting = false;
262
+ return;
263
+ }
264
+
265
+ isRestarting = true;
266
+ const delay = BACKOFF_DELAYS[Math.min(restartAttempts, BACKOFF_DELAYS.length - 1)];
267
+ restartAttempts++;
268
+
269
+ log.info(`Restarting tunnel in ${delay}ms (attempt ${restartAttempts}/${MAX_RESTART_ATTEMPTS})`);
270
+ tunnelEvents.emit('reconnecting', { attempt: restartAttempts, delay });
271
+
272
+ restartTimer = setTimeout(async () => {
273
+ restartTimer = null;
274
+ try {
275
+ const result = await hostTunnel();
276
+ if (result) {
277
+ log.info('Tunnel reconnected successfully');
278
+ restartAttempts = 0;
279
+ isRestarting = false;
280
+ tunnelEvents.emit('connected', { url: result.url });
281
+ startHealthCheck();
282
+ } else {
283
+ log.warn('Tunnel restart returned no URL');
284
+ isRestarting = false;
285
+ scheduleRestart();
286
+ }
287
+ } catch (err) {
288
+ log.error(`Tunnel restart error: ${err.message}`);
289
+ isRestarting = false;
290
+ scheduleRestart();
291
+ }
292
+ }, delay);
293
+ restartTimer.unref();
294
+ }
295
+
296
+ /**
297
+ * Spawn `devtunnel host` for the current tunnelId and wait for the URL.
298
+ * Used by both initial start and watchdog restarts.
299
+ */
300
+ function hostTunnel() {
301
+ const hostProc = spawn(devtunnelCmd, ['host', tunnelId], {
302
+ stdio: ['pipe', 'pipe', 'pipe'],
303
+ });
304
+ tunnelProc = hostProc;
305
+
306
+ // Attach exit handler for crash detection
307
+ hostProc.on('exit', (code, signal) => {
308
+ if (tunnelProc !== hostProc) return; // stale reference
309
+ log.warn(`Tunnel process exited (code=${code}, signal=${signal})`);
310
+ tunnelProc = null;
311
+ if (!isRestarting) {
312
+ tunnelEvents.emit('disconnected');
313
+ scheduleRestart();
314
+ }
315
+ });
316
+
317
+ return new Promise((resolve) => {
318
+ let output = '';
319
+ const timeout = setTimeout(() => {
320
+ // Kill the process if URL wasn't detected in time
321
+ try {
322
+ hostProc.kill('SIGKILL');
323
+ } catch {
324
+ /* best effort */
325
+ }
326
+ if (tunnelProc === hostProc) tunnelProc = null;
327
+ resolve(null);
328
+ }, 15_000);
329
+
330
+ hostProc.stdout.on('data', (data) => {
331
+ output += data.toString();
332
+ const match = output.match(/(https:\/\/[^\s]+devtunnels\.ms[^\s]*)/);
333
+ if (match) {
334
+ clearTimeout(timeout);
335
+ resolve({ url: match[1] });
336
+ }
337
+ });
338
+ hostProc.stderr.on('data', (data) => {
339
+ output += data.toString();
340
+ });
341
+ hostProc.on('error', (err) => {
342
+ log.error(`Tunnel process error: ${err.message}`);
343
+ clearTimeout(timeout);
344
+ resolve(null);
345
+ });
346
+ });
347
+ }
348
+
138
349
  async function startTunnel(port, options = {}) {
139
350
  // Check if devtunnel CLI is installed
140
351
  let found = findDevtunnel();
@@ -254,32 +465,14 @@ async function startTunnel(port, options = {}) {
254
465
  log.info('Tunnel access: private (owner-only via Microsoft login)');
255
466
  }
256
467
 
257
- const hostProc = spawn(devtunnelCmd, ['host', tunnelId], {
258
- stdio: ['pipe', 'pipe', 'pipe'],
259
- });
260
- tunnelProc = hostProc;
261
-
262
- return new Promise((resolve) => {
263
- let output = '';
264
- const timeout = setTimeout(() => resolve(null), 15000);
265
-
266
- hostProc.stdout.on('data', (data) => {
267
- output += data.toString();
268
- const match = output.match(/(https:\/\/[^\s]+devtunnels\.ms[^\s]*)/);
269
- if (match) {
270
- clearTimeout(timeout);
271
- resolve({ url: match[1], mode: tunnelMode, expiry: tunnelExpiry });
272
- }
273
- });
274
- hostProc.stderr.on('data', (data) => {
275
- output += data.toString();
276
- });
277
- hostProc.on('error', (err) => {
278
- log.error(`Tunnel process error: ${err.message}`);
279
- clearTimeout(timeout);
280
- resolve(null);
281
- });
282
- });
468
+ const result = await hostTunnel();
469
+ if (result) {
470
+ result.mode = tunnelMode;
471
+ result.expiry = tunnelExpiry;
472
+ startHealthCheck();
473
+ tunnelEvents.emit('connected', { url: result.url });
474
+ }
475
+ return result;
283
476
  } catch (e) {
284
477
  log.error(`Tunnel error: ${e.message}`);
285
478
  return null;
@@ -287,6 +480,14 @@ async function startTunnel(port, options = {}) {
287
480
  }
288
481
 
289
482
  function cleanupTunnel() {
483
+ // Stop watchdog first to prevent restart during cleanup
484
+ stopHealthCheck();
485
+ isRestarting = true; // prevent exit handler from restarting
486
+ if (restartTimer) {
487
+ clearTimeout(restartTimer);
488
+ restartTimer = null;
489
+ }
490
+
290
491
  const id = tunnelId;
291
492
  if (tunnelProc) {
292
493
  try {
@@ -321,6 +522,11 @@ function cleanupTunnel() {
321
522
  }
322
523
  }
323
524
  }
525
+
526
+ // Reset watchdog state
527
+ consecutiveFailures = 0;
528
+ restartAttempts = 0;
529
+ isRestarting = false;
324
530
  }
325
531
 
326
- module.exports = { startTunnel, cleanupTunnel, findDevtunnel };
532
+ module.exports = { startTunnel, cleanupTunnel, findDevtunnel, tunnelEvents };
@@ -1 +0,0 @@
1
- import{aq as o,ar as n}from"./index-pqtccC7s.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-DY15q7Tk.js";import{_ as i}from"./index-pqtccC7s.js";import"./chunk-FMBD7UC4-cK52FAx0.js";import"./chunk-JSJVCQXG-CudZY5_F.js";import"./chunk-55IACEB6-CRSrEoDB.js";import"./chunk-KX2RTZJC-BZlXzthI.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-DY15q7Tk.js";import{_ as i}from"./index-pqtccC7s.js";import"./chunk-FMBD7UC4-cK52FAx0.js";import"./chunk-JSJVCQXG-CudZY5_F.js";import"./chunk-55IACEB6-CRSrEoDB.js";import"./chunk-KX2RTZJC-BZlXzthI.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{b as r}from"./_baseUniq-CmudMx6k.js";var e=4;function a(o){return r(o,e)}export{a as c};
@@ -1 +0,0 @@
1
- import{s as t,b as r,a,S as s}from"./chunk-NQ4KR5QH-BP6XJFdX.js";import{_ as i}from"./index-pqtccC7s.js";import"./chunk-55IACEB6-CRSrEoDB.js";import"./chunk-KX2RTZJC-BZlXzthI.js";var l={parser:a,get db(){return new s(2)},renderer:r,styles:t,init:i(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")};export{l as diagram};