From 701d39982fbd459d668261582a69b03a727becd5 Mon Sep 17 00:00:00 2001 From: Zaine Date: Sun, 28 Jun 2026 22:31:02 +0100 Subject: [PATCH] expanding context of ai --- apps/web/public/sw.js | 2 +- apps/web/src/lib/services/ai-context.test.ts | 17 ++ apps/web/src/lib/services/ai-context.ts | 170 ++++++++++++++++++- apps/web/src/lib/services/ai.ts | 1 + 4 files changed, 186 insertions(+), 4 deletions(-) mode change 100755 => 100644 apps/web/public/sw.js diff --git a/apps/web/public/sw.js b/apps/web/public/sw.js old mode 100755 new mode 100644 index 2510551..562baa8 --- a/apps/web/public/sw.js +++ b/apps/web/public/sw.js @@ -1,2 +1,2 @@ (()=>{"use strict";let e,t,a,s,r,n={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"serwist",runtime:"runtime",suffix:"u">typeof registration?registration.scope:""},i=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join("-"),c=e=>e||i(n.precache),o=e=>e||i(n.runtime);var l=class extends Error{details;constructor(e,t){super(((e,...t)=>{let a=e;return t.length>0&&(a+=` :: ${JSON.stringify(t)}`),a})(e,t)),this.name=e,this.details=t}};function h(e){return new Promise(t=>setTimeout(t,e))}let u=new Set;function d(e,t){let a=new URL(e);for(let e of t)a.searchParams.delete(e);return a.href}async function m(e,t,a,s){let r=d(t.url,a);if(t.url===r)return e.match(t,s);let n={...s,ignoreSearch:!0};for(let i of(await e.keys(t,n)))if(r===d(i.url,a))return e.match(i,s)}var f=class{promise;resolve;reject;constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}};let g=async()=>{for(let e of u)await e()},w="-precache-",p=async(e,t=w)=>{let a=(await self.caches.keys()).filter(a=>a.includes(t)&&a.includes(self.registration.scope)&&a!==e);return await Promise.all(a.map(e=>self.caches.delete(e))),a},y=(e,t)=>{let a=t();return e.waitUntil(a),a},_=(e,t)=>t.some(t=>e instanceof t),x=new WeakMap,b=new WeakMap,v=new WeakMap,E={get(e,t,a){if(e instanceof IDBTransaction){if("done"===t)return x.get(e);if("store"===t)return a.objectStoreNames[1]?void 0:a.objectStore(a.objectStoreNames[0])}return R(e[t])},set:(e,t,a)=>(e[t]=a,!0),has:(e,t)=>e instanceof IDBTransaction&&("done"===t||"store"===t)||t in e};function R(e){if(e instanceof IDBRequest){let t;return t=new Promise((t,a)=>{let s=()=>{e.removeEventListener("success",r),e.removeEventListener("error",n)},r=()=>{t(R(e.result)),s()},n=()=>{a(e.error),s()};e.addEventListener("success",r),e.addEventListener("error",n)}),v.set(t,e),t}if(b.has(e))return b.get(e);let t=function(e){if("function"==typeof e)return(r||(r=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(e)?function(...t){return e.apply(q(this),t),R(this.request)}:function(...t){return R(e.apply(q(this),t))};return(e instanceof IDBTransaction&&function(e){if(x.has(e))return;let t=new Promise((t,a)=>{let s=()=>{e.removeEventListener("complete",r),e.removeEventListener("error",n),e.removeEventListener("abort",n)},r=()=>{t(),s()},n=()=>{a(e.error||new DOMException("AbortError","AbortError")),s()};e.addEventListener("complete",r),e.addEventListener("error",n),e.addEventListener("abort",n)});x.set(e,t)}(e),_(e,s||(s=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])))?new Proxy(e,E):e}(e);return t!==e&&(b.set(e,t),v.set(t,e)),t}let q=e=>v.get(e);function S(e,t,{blocked:a,upgrade:s,blocking:r,terminated:n}={}){let i=indexedDB.open(e,t),c=R(i);return s&&i.addEventListener("upgradeneeded",e=>{s(R(i.result),e.oldVersion,e.newVersion,R(i.transaction),e)}),a&&i.addEventListener("blocked",e=>a(e.oldVersion,e.newVersion,e)),c.then(e=>{n&&e.addEventListener("close",()=>n()),r&&e.addEventListener("versionchange",e=>r(e.oldVersion,e.newVersion,e))}).catch(()=>{}),c}let D=["get","getKey","getAll","getAllKeys","count"],N=["put","add","delete","clear"],C=new Map;function T(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&"string"==typeof t))return;if(C.get(t))return C.get(t);let a=t.replace(/FromIndex$/,""),s=t!==a,r=N.includes(a);if(!(a in(s?IDBIndex:IDBObjectStore).prototype)||!(r||D.includes(a)))return;let n=async function(e,...t){let n=this.transaction(e,r?"readwrite":"readonly"),i=n.store;return s&&(i=i.index(t.shift())),(await Promise.all([i[a](...t),r&&n.done]))[0]};return C.set(t,n),n}E={...e=E,get:(t,a,s)=>T(t,a)||e.get(t,a,s),has:(t,a)=>!!T(t,a)||e.has(t,a)};let P=["continue","continuePrimaryKey","advance"],k={},A=new WeakMap,I=new WeakMap,U={get(e,t){if(!P.includes(t))return e[t];let a=k[t];return a||(a=k[t]=function(...e){A.set(this,I.get(this)[t](...e))}),a}};async function*L(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;let a=new Proxy(t,U);for(I.set(a,t),v.set(a,q(t));t;)yield a,t=await (A.get(a)||t.continue()),A.delete(a)}function F(e,t){return t===Symbol.asyncIterator&&_(e,[IDBIndex,IDBObjectStore,IDBCursor])||"iterate"===t&&_(e,[IDBIndex,IDBObjectStore])}E={...t=E,get:(e,a,s)=>F(e,a)?L:t.get(e,a,s),has:(e,a)=>F(e,a)||t.has(e,a)};let M=async(e,t)=>{let s=null;if(e.url&&(s=new URL(e.url).origin),s!==self.location.origin)throw new l("cross-origin-copy-response",{origin:s});let r=e.clone(),n={headers:new Headers(r.headers),status:r.status,statusText:r.statusText},i=t?t(n):n,c=!function(){if(void 0===a){let e=new Response("");if("body"in e)try{new Response(e.body),a=!0}catch{a=!1}a=!1}return a}()?await r.blob():r.body;return new Response(c,i)},O="requests",B="queueName";var K=class{_db=null;async addEntry(e){let t=(await this.getDb()).transaction(O,"readwrite",{durability:"relaxed"});await t.store.add(e),await t.done}async getFirstEntryId(){return(await (await this.getDb()).transaction(O).store.openCursor())?.value.id}async getAllEntriesByQueueName(e){return await (await this.getDb()).getAllFromIndex(O,B,IDBKeyRange.only(e))||[]}async getEntryCountByQueueName(e){return(await this.getDb()).countFromIndex(O,B,IDBKeyRange.only(e))}async deleteEntry(e){await (await this.getDb()).delete(O,e)}async getFirstEntryByQueueName(e){return await this.getEndEntryFromIndex(IDBKeyRange.only(e),"next")}async getLastEntryByQueueName(e){return await this.getEndEntryFromIndex(IDBKeyRange.only(e),"prev")}async getEndEntryFromIndex(e,t){return(await (await this.getDb()).transaction(O).store.index(B).openCursor(e,t))?.value}async getDb(){return this._db||(this._db=await S("serwist-background-sync",3,{upgrade:this._upgradeDb})),this._db}_upgradeDb(e,t){t>0&&t<3&&e.objectStoreNames.contains(O)&&e.deleteObjectStore(O),e.createObjectStore(O,{autoIncrement:!0,keyPath:"id"}).createIndex(B,B,{unique:!1})}},W=class{_queueName;_queueDb;constructor(e){this._queueName=e,this._queueDb=new K}async pushEntry(e){delete e.id,e.queueName=this._queueName,await this._queueDb.addEntry(e)}async unshiftEntry(e){let t=await this._queueDb.getFirstEntryId();t?e.id=t-1:delete e.id,e.queueName=this._queueName,await this._queueDb.addEntry(e)}async popEntry(){return this._removeEntry(await this._queueDb.getLastEntryByQueueName(this._queueName))}async shiftEntry(){return this._removeEntry(await this._queueDb.getFirstEntryByQueueName(this._queueName))}async getAll(){return await this._queueDb.getAllEntriesByQueueName(this._queueName)}async size(){return await this._queueDb.getEntryCountByQueueName(this._queueName)}async deleteEntry(e){await this._queueDb.deleteEntry(e)}async _removeEntry(e){return e&&await this.deleteEntry(e.id),e}};let j=["method","referrer","referrerPolicy","mode","credentials","cache","redirect","integrity","keepalive"];var $=class e{_requestData;static async fromRequest(t){let a={url:t.url,headers:{}};for(let e of("GET"!==t.method&&(a.body=await t.clone().arrayBuffer()),t.headers.forEach((e,t)=>{a.headers[t]=e}),j))void 0!==t[e]&&(a[e]=t[e]);return new e(a)}constructor(e){"navigate"===e.mode&&(e.mode="same-origin"),this._requestData=e}toObject(){let e=Object.assign({},this._requestData);return e.headers=Object.assign({},this._requestData.headers),e.body&&(e.body=e.body.slice(0)),e}toRequest(){return new Request(this._requestData.url,this._requestData)}clone(){return new e(this.toObject())}};let H="serwist-background-sync",G=new Set,Q=e=>{let t={request:new $(e.requestData).toRequest(),timestamp:e.timestamp};return e.metadata&&(t.metadata=e.metadata),t};var V=class{_name;_onSync;_maxRetentionTime;_queueStore;_forceSyncFallback;_syncInProgress=!1;_requestsAddedDuringSync=!1;constructor(e,{forceSyncFallback:t,onSync:a,maxRetentionTime:s}={}){if(G.has(e))throw new l("duplicate-queue-name",{name:e});G.add(e),this._name=e,this._onSync=a||this.replayRequests,this._maxRetentionTime=s||10080,this._forceSyncFallback=!!t,this._queueStore=new W(this._name),this._addSyncListener()}get name(){return this._name}async pushRequest(e){await this._addRequest(e,"push")}async unshiftRequest(e){await this._addRequest(e,"unshift")}async popRequest(){return this._removeRequest("pop")}async shiftRequest(){return this._removeRequest("shift")}async getAll(){let e=await this._queueStore.getAll(),t=Date.now(),a=[];for(let s of e){let e=60*this._maxRetentionTime*1e3;t-s.timestamp>e?await this._queueStore.deleteEntry(s.id):a.push(Q(s))}return a}async size(){return await this._queueStore.size()}async _addRequest({request:e,metadata:t,timestamp:a=Date.now()},s){let r={requestData:(await $.fromRequest(e.clone())).toObject(),timestamp:a};switch(t&&(r.metadata=t),s){case"push":await this._queueStore.pushEntry(r);break;case"unshift":await this._queueStore.unshiftEntry(r)}this._syncInProgress?this._requestsAddedDuringSync=!0:await this.registerSync()}async _removeRequest(e){let t,a=Date.now();switch(e){case"pop":t=await this._queueStore.popEntry();break;case"shift":t=await this._queueStore.shiftEntry()}if(t){let s=60*this._maxRetentionTime*1e3;return a-t.timestamp>s?this._removeRequest(e):Q(t)}}async replayRequests(){let e;for(;e=await this.shiftRequest();)try{await fetch(e.request.clone())}catch{throw await this.unshiftRequest(e),new l("queue-replay-failed",{name:this._name})}}async registerSync(){if("sync"in self.registration&&!this._forceSyncFallback)try{await self.registration.sync.register(`${H}:${this._name}`)}catch(e){}}_addSyncListener(){"sync"in self.registration&&!this._forceSyncFallback?self.addEventListener("sync",e=>{if(e.tag===`${H}:${this._name}`){let t=async()=>{let t;this._syncInProgress=!0;try{await this._onSync({queue:this})}catch(e){if(e instanceof Error)throw e}finally{this._requestsAddedDuringSync&&!(t&&!e.lastChance)&&await this.registerSync(),this._syncInProgress=!1,this._requestsAddedDuringSync=!1}};e.waitUntil(t())}}):this._onSync({queue:this})}static get _queueNames(){return G}},z=class{_queue;constructor(e,t){this._queue=new V(e,t)}async fetchDidFail({request:e}){await this._queue.pushRequest({request:e})}};let J={cacheWillUpdate:async({response:e})=>200===e.status||0===e.status?e:null};function X(e){return"string"==typeof e?new Request(e):e}var Y=class{event;request;url;params;_cacheKeys={};_strategy;_handlerDeferred;_extendLifetimePromises;_plugins;_pluginStateMap;constructor(e,t){for(const a of(this.event=t.event,this.request=t.request,t.url&&(this.url=t.url,this.params=t.params),this._strategy=e,this._handlerDeferred=new f,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map,this._plugins))this._pluginStateMap.set(a,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:t}=this,a=X(e),s=await this.getPreloadResponse();if(s)return s;let r=this.hasCallback("fetchDidFail")?a.clone():null;try{for(let e of this.iterateCallbacks("requestWillFetch"))a=await e({request:a.clone(),event:t})}catch(e){if(e instanceof Error)throw new l("plugin-error-request-will-fetch",{thrownErrorMessage:e.message})}let n=a.clone();try{let e;for(let s of(e=await fetch(a,"navigate"===a.mode?void 0:this._strategy.fetchOptions),this.iterateCallbacks("fetchDidSucceed")))e=await s({event:t,request:n,response:e});return e}catch(e){throw r&&await this.runCallbacks("fetchDidFail",{error:e,event:t,originalRequest:r.clone(),request:n.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),a=t.clone();return this.waitUntil(this.cachePut(e,a)),t}async cacheMatch(e){let t,a=X(e),{cacheName:s,matchOptions:r}=this._strategy,n=await this.getCacheKey(a,"read"),i={...r,cacheName:s};for(let e of(t=await caches.match(n,i),this.iterateCallbacks("cachedResponseWillBeUsed")))t=await e({cacheName:s,matchOptions:r,cachedResponse:t,request:n,event:this.event})||void 0;return t}async cachePut(e,t){let a=X(e);await h(0);let s=await this.getCacheKey(a,"write");if(!t)throw new l("cache-put-with-no-response",{url:new URL(String(s.url),location.href).href.replace(RegExp(`^${location.origin}`),"")});let r=await this._ensureResponseSafeToCache(t);if(!r)return!1;let{cacheName:n,matchOptions:i}=this._strategy,c=await self.caches.open(n),o=this.hasCallback("cacheDidUpdate"),u=o?await m(c,s.clone(),["__WB_REVISION__"],i):null;try{await c.put(s,o?r.clone():r)}catch(e){if(e instanceof Error)throw"QuotaExceededError"===e.name&&await g(),e}for(let e of this.iterateCallbacks("cacheDidUpdate"))await e({cacheName:n,oldResponse:u,newResponse:r.clone(),request:s,event:this.event});return!0}async getCacheKey(e,t){let a=`${e.url} | ${t}`;if(!this._cacheKeys[a]){let s=e;for(let e of this.iterateCallbacks("cacheKeyWillBeUsed"))s=X(await e({mode:t,request:s,event:this.event,params:this.params}));this._cacheKeys[a]=s}return this._cacheKeys[a]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let a of this.iterateCallbacks(e))await a(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if("function"==typeof t[e]){let a=this._pluginStateMap.get(t),s=s=>{let r={...s,state:a};return t[e](r)};yield s}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){let e;for(;e=this._extendLifetimePromises.shift();)await e}destroy(){this._handlerDeferred.resolve(null)}async getPreloadResponse(){if(this.event instanceof FetchEvent&&"navigate"===this.event.request.mode&&"preloadResponse"in this.event)try{let e=await this.event.preloadResponse;if(e)return e}catch(e){return}}async _ensureResponseSafeToCache(e){let t=e,a=!1;for(let e of this.iterateCallbacks("cacheWillUpdate"))if(t=await e({request:this.request,response:t,event:this.event})||void 0,a=!0,!t)break;return!a&&t&&200!==t.status&&(t=void 0),t}},Z=class{cacheName;plugins;fetchOptions;matchOptions;constructor(e={}){this.cacheName=o(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,a="string"==typeof e.request?new Request(e.request):e.request,s=new Y(this,e.url?{event:t,request:a,url:e.url,params:e.params}:{event:t,request:a}),r=this._getResponse(s,a,t);return[r,this._awaitComplete(r,s,a,t)]}async _getResponse(e,t,a){let s;await e.runCallbacks("handlerWillStart",{event:a,request:t});try{if(s=await this._handle(t,e),void 0===s||"error"===s.type)throw new l("no-response",{url:t.url})}catch(r){if(r instanceof Error){for(let n of e.iterateCallbacks("handlerDidError"))if(void 0!==(s=await n({error:r,event:a,request:t})))break}if(!s)throw r}for(let r of e.iterateCallbacks("handlerWillRespond"))s=await r({event:a,request:t,response:s});return s}async _awaitComplete(e,t,a,s){let r,n;try{r=await e}catch{}try{await t.runCallbacks("handlerDidRespond",{event:s,request:a,response:r}),await t.doneWaiting()}catch(e){e instanceof Error&&(n=e)}if(await t.runCallbacks("handlerDidComplete",{event:s,request:a,response:r,error:n}),t.destroy(),n)throw n}},ee=class extends Z{_networkTimeoutSeconds;constructor(e={}){super(e),this.plugins.some(e=>"cacheWillUpdate"in e)||this.plugins.unshift(J),this._networkTimeoutSeconds=e.networkTimeoutSeconds||0}async _handle(e,t){let a,s=[],r=[];if(this._networkTimeoutSeconds){let{id:n,promise:i}=this._getTimeoutPromise({request:e,logs:s,handler:t});a=n,r.push(i)}let n=this._getNetworkPromise({timeoutId:a,request:e,logs:s,handler:t});r.push(n);let i=await t.waitUntil((async()=>await t.waitUntil(Promise.race(r))||await n)());if(!i)throw new l("no-response",{url:e.url});return i}_getTimeoutPromise({request:e,logs:t,handler:a}){let s;return{promise:new Promise(t=>{s=setTimeout(async()=>{t(await a.cacheMatch(e))},1e3*this._networkTimeoutSeconds)}),id:s}}async _getNetworkPromise({timeoutId:e,request:t,logs:a,handler:s}){let r,n;try{n=await s.fetchAndCachePut(t)}catch(e){e instanceof Error&&(r=e)}return e&&clearTimeout(e),(r||!n)&&(n=await s.cacheMatch(t)),n}},et=class extends Z{_networkTimeoutSeconds;constructor(e={}){super(e),this._networkTimeoutSeconds=e.networkTimeoutSeconds||0}async _handle(e,t){let a,s;try{let a=[t.fetch(e)];if(this._networkTimeoutSeconds){let e=h(1e3*this._networkTimeoutSeconds);a.push(e)}if(!(s=await Promise.race(a)))throw Error(`Timed out the network response after ${this._networkTimeoutSeconds} seconds.`)}catch(e){e instanceof Error&&(a=e)}if(!s)throw new l("no-response",{url:e.url,error:a});return s}};let ea=e=>e&&"object"==typeof e?e:{handle:e};var es=class{handler;match;method;catchHandler;constructor(e,t,a="GET"){this.handler=ea(t),this.match=e,this.method=a}setCatchHandler(e){this.catchHandler=ea(e)}},er=class e extends Z{_fallbackToNetwork;static defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:e})=>!e||e.status>=400?null:e};static copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:e})=>e.redirected?await M(e):e};constructor(t={}){t.cacheName=c(t.cacheName),super(t),this._fallbackToNetwork=!1!==t.fallbackToNetwork,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){let a=await t.getPreloadResponse();if(a)return a;let s=await t.cacheMatch(e);return s||(t.event&&"install"===t.event.type?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,t){let a,s=t.params||{};if(this._fallbackToNetwork){let r=s.integrity,n=e.integrity,i=!n||n===r;a=await t.fetch(new Request(e,{integrity:"no-cors"!==e.mode?n||r:void 0})),r&&i&&"no-cors"!==e.mode&&(this._useDefaultCacheabilityPluginIfNeeded(),await t.cachePut(e,a.clone()))}else throw new l("missing-precache-entry",{cacheName:this.cacheName,url:e.url});return a}async _handleInstall(e,t){this._useDefaultCacheabilityPluginIfNeeded();let a=await t.fetch(e);if(!await t.cachePut(e,a.clone()))throw new l("bad-precaching-response",{url:e.url,status:a.status});return a}_useDefaultCacheabilityPluginIfNeeded(){let t=null,a=0;for(let[s,r]of this.plugins.entries())r!==e.copyRedirectedCacheableResponsesPlugin&&(r===e.defaultPrecacheCacheabilityPlugin&&(t=s),r.cacheWillUpdate&&a++);0===a?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):a>1&&null!==t&&this.plugins.splice(t,1)}},en=class extends es{_allowlist;_denylist;constructor(e,{allowlist:t=[/./],denylist:a=[]}={}){super(e=>this._match(e),e),this._allowlist=t,this._denylist=a}_match({url:e,request:t}){if(t&&"navigate"!==t.mode)return!1;let a=e.pathname+e.search;for(let e of this._denylist)if(e.test(a))return!1;return!!this._allowlist.some(e=>e.test(a))}},ei=class extends es{constructor(e,t,a){super(({url:t})=>{let a=e.exec(t.href);if(a)return t.origin!==location.origin&&0!==a.index?void 0:a.slice(1)},t,a)}};let ec=e=>{if(!e)throw new l("add-to-cache-list-unexpected-type",{entry:e});if("string"==typeof e){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:t,url:a}=e;if(!a)throw new l("add-to-cache-list-unexpected-type",{entry:e});if(!t){let e=new URL(a,location.href);return{cacheKey:e.href,url:e.href}}let s=new URL(a,location.href),r=new URL(a,location.href);return s.searchParams.set("__WB_REVISION__",t),{cacheKey:s.href,url:r.href}};var eo=class{updatedURLs=[];notUpdatedURLs=[];handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)};cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:a})=>{if("install"===e.type&&t?.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;a?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return a}};let el=async(e,t,a)=>{let s=t.map((e,t)=>({index:t,item:e})),r=async e=>{let t=[];for(;;){let r=s.pop();if(!r)return e(t);let n=await a(r.item);t.push({result:n,index:r.index})}},n=Array.from({length:e},()=>new Promise(r));return(await Promise.all(n)).flat().sort((e,t)=>e.indexe.result)};"u">typeof navigator&&/^((?!chrome|android).)*safari/i.test(navigator.userAgent);let eh="cache-entries",eu=e=>{let t=new URL(e,location.href);return t.hash="",t.href};var ed=class{_cacheName;_db=null;constructor(e){this._cacheName=e}_getId(e){return`${this._cacheName}|${eu(e)}`}_upgradeDb(e){let t=e.createObjectStore(eh,{keyPath:"id"});t.createIndex("cacheName","cacheName",{unique:!1}),t.createIndex("timestamp","timestamp",{unique:!1})}_upgradeDbAndDeleteOldDbs(e){this._upgradeDb(e),this._cacheName&&function(e,{blocked:t}={}){let a=indexedDB.deleteDatabase(e);t&&a.addEventListener("blocked",e=>t(e.oldVersion,e)),R(a).then(()=>void 0)}(this._cacheName)}async setTimestamp(e,t){e=eu(e);let a={id:this._getId(e),cacheName:this._cacheName,url:e,timestamp:t},s=(await this.getDb()).transaction(eh,"readwrite",{durability:"relaxed"});await s.store.put(a),await s.done}async getTimestamp(e){return(await (await this.getDb()).get(eh,this._getId(e)))?.timestamp}async expireEntries(e,t){let a=await (await this.getDb()).transaction(eh,"readwrite").store.index("timestamp").openCursor(null,"prev"),s=[],r=0;for(;a;){let n=a.value;n.cacheName===this._cacheName&&(e&&n.timestamp=t?(a.delete(),s.push(n.url)):r++),a=await a.continue()}return s}async getDb(){return this._db||(this._db=await S("serwist-expiration",1,{upgrade:this._upgradeDbAndDeleteOldDbs.bind(this)})),this._db}},em=class{_isRunning=!1;_rerunRequested=!1;_maxEntries;_maxAgeSeconds;_matchOptions;_cacheName;_timestampModel;constructor(e,t={}){this._maxEntries=t.maxEntries,this._maxAgeSeconds=t.maxAgeSeconds,this._matchOptions=t.matchOptions,this._cacheName=e,this._timestampModel=new ed(e)}async expireEntries(){if(this._isRunning){this._rerunRequested=!0;return}this._isRunning=!0;let e=this._maxAgeSeconds?Date.now()-1e3*this._maxAgeSeconds:0,t=await this._timestampModel.expireEntries(e,this._maxEntries),a=await self.caches.open(this._cacheName);for(let e of t)await a.delete(e,this._matchOptions);this._isRunning=!1,this._rerunRequested&&(this._rerunRequested=!1,this.expireEntries())}async updateTimestamp(e){await this._timestampModel.setTimestamp(e,Date.now())}async isURLExpired(e){if(!this._maxAgeSeconds)return!1;let t=await this._timestampModel.getTimestamp(e),a=Date.now()-1e3*this._maxAgeSeconds;return void 0===t||t{u.add(e)})(()=>this.deleteCacheAndMetadata())}_getCacheExpiration(e){if(e===o())throw new l("expire-custom-caches-only");let t=this._cacheExpirations.get(e);return t||(t=new em(e,this._config),this._cacheExpirations.set(e,t)),t}cachedResponseWillBeUsed({event:e,cacheName:t,request:a,cachedResponse:s}){if(!s)return null;let r=this._isResponseDateFresh(s),n=this._getCacheExpiration(t),i="last-used"===this._config.maxAgeFrom,c=(async()=>{i&&await n.updateTimestamp(a.url),await n.expireEntries()})();try{e.waitUntil(c)}catch{}return r?s:null}_isResponseDateFresh(e){if("last-used"===this._config.maxAgeFrom)return!0;let t=Date.now();if(!this._config.maxAgeSeconds)return!0;let a=this._getDateHeaderTimestamp(e);return null===a||a>=t-1e3*this._config.maxAgeSeconds}_getDateHeaderTimestamp(e){if(!e.headers.has("date"))return null;let t=new Date(e.headers.get("date")).getTime();return Number.isNaN(t)?null:t}async cacheDidUpdate({cacheName:e,request:t}){let a=this._getCacheExpiration(e);await a.updateTimestamp(t.url),await a.expireEntries()}async deleteCacheAndMetadata(){for(let[e,t]of this._cacheExpirations)await self.caches.delete(e),await t.delete();this._cacheExpirations=new Map}};let eg=/^\/(\w+\/)?collect/,ew=({serwist:e,cacheName:t,...a})=>{let s,r,c=t||i(n.googleAnalytics),o=new z("serwist-google-analytics",{maxRetentionTime:2880,onSync:async({queue:e})=>{let t;for(;t=await e.shiftRequest();){let{request:s,timestamp:r}=t,n=new URL(s.url);try{let e="POST"===s.method?new URLSearchParams(await s.clone().text()):n.searchParams,t=r-(Number(e.get("qt"))||0),i=Date.now()-t;if(e.set("qt",String(i)),a.parameterOverrides)for(let t of Object.keys(a.parameterOverrides)){let s=a.parameterOverrides[t];e.set(t,s)}"function"==typeof a.hitFilter&&a.hitFilter.call(null,e),await fetch(new Request(n.origin+n.pathname,{body:e.toString(),method:"POST",mode:"cors",credentials:"omit",headers:{"Content-Type":"text/plain"}}))}catch(a){throw await e.unshiftRequest(t),a}}}});for(let t of[new es(({url:e})=>"www.googletagmanager.com"===e.hostname&&"/gtm.js"===e.pathname,new ee({cacheName:c}),"GET"),new es(({url:e})=>"www.google-analytics.com"===e.hostname&&"/analytics.js"===e.pathname,new ee({cacheName:c}),"GET"),new es(({url:e})=>"www.googletagmanager.com"===e.hostname&&"/gtag/js"===e.pathname,new ee({cacheName:c}),"GET"),new es(s=({url:e})=>"www.google-analytics.com"===e.hostname&&eg.test(e.pathname),r=new et({plugins:[o]}),"GET"),new es(s,r,"POST")])e.registerRoute(t)};var ep=class{_fallbackUrls;_serwist;constructor({fallbackUrls:e,serwist:t}){this._fallbackUrls=e,this._serwist=t}async handlerDidError(e){for(let t of this._fallbackUrls)if("string"==typeof t){let e=await this._serwist.matchPrecache(t);if(void 0!==e)return e}else if(t.matcher(e)){let e=await this._serwist.matchPrecache(t.url);if(void 0!==e)return e}}};let ey=async(e,t)=>{try{if(206===t.status)return t;let a=e.headers.get("range");if(!a)throw new l("no-range-header");let s=(e=>{let t=e.trim().toLowerCase();if(!t.startsWith("bytes="))throw new l("unit-must-be-bytes",{normalizedRangeHeader:t});if(t.includes(","))throw new l("single-range-only",{normalizedRangeHeader:t});let a=/(\d*)-(\d*)/.exec(t);if(!a||!(a[1]||a[2]))throw new l("invalid-range-values",{normalizedRangeHeader:t});return{start:""===a[1]?void 0:Number(a[1]),end:""===a[2]?void 0:Number(a[2])}})(a),r=await t.blob(),n=((e,t,a)=>{let s,r,n=e.size;if(a&&a>n||t&&t<0)throw new l("range-not-satisfiable",{size:n,end:a,start:t});return void 0!==t&&void 0!==a?(s=t,r=a+1):void 0!==t&&void 0===a?(s=t,r=n):void 0!==a&&void 0===t&&(s=n-a,r=n),{start:s,end:r}})(r,s.start,s.end),i=r.slice(n.start,n.end),c=i.size,o=new Response(i,{status:206,statusText:"Partial Content",headers:t.headers});return o.headers.set("Content-Length",String(c)),o.headers.set("Content-Range",`bytes ${n.start}-${n.end-1}/${r.size}`),o}catch(e){return new Response("",{status:416,statusText:"Range Not Satisfiable"})}};var e_=class{cachedResponseWillBeUsed=async({request:e,cachedResponse:t})=>t&&e.headers.has("range")?await ey(e,t):t},ex=class extends Z{async _handle(e,t){let a,s=await t.cacheMatch(e);if(s);else try{s=await t.fetchAndCachePut(e)}catch(e){e instanceof Error&&(a=e)}if(!s)throw new l("no-response",{url:e.url,error:a});return s}},eb=class extends Z{constructor(e={}){super(e),this.plugins.some(e=>"cacheWillUpdate"in e)||this.plugins.unshift(J)}async _handle(e,t){let a,s=t.fetchAndCachePut(e).catch(()=>{});t.waitUntil(s);let r=await t.cacheMatch(e);if(r);else try{r=await s}catch(e){e instanceof Error&&(a=e)}if(!r)throw new l("no-response",{url:e.url,error:a});return r}},ev=class extends es{constructor(e,t){super(({request:a})=>{let s=e.getUrlsToPrecacheKeys();for(let r of function*(e,{directoryIndex:t="index.html",ignoreURLParametersMatching:a=[/^utm_/,/^fbclid$/],cleanURLs:s=!0,urlManipulation:r}={}){let n=new URL(e,location.href);n.hash="",yield n.href;let i=((e,t=[])=>{for(let a of[...e.searchParams.keys()])t.some(e=>e.test(a))&&e.searchParams.delete(a);return e})(n,a);if(yield i.href,t&&i.pathname.endsWith("/")){let e=new URL(i.href);e.pathname+=t,yield e.href}if(s){let e=new URL(i.href);e.pathname+=".html",yield e.href}if(r)for(let e of r({url:n}))yield e.href}(a.url,t)){let t=s.get(r);if(t)return{cacheKey:t,integrity:e.getIntegrityForPrecacheKey(t)}}},e.precacheStrategy)}},eE=class{_precacheController;constructor({precacheController:e}){this._precacheController=e}cacheKeyWillBeUsed=async({request:e,params:t})=>{let a=t?.cacheKey||this._precacheController.getPrecacheKeyForUrl(e.url);return a?new Request(a,{headers:e.headers}):e}},eR=class{_urlsToCacheKeys=new Map;_urlsToCacheModes=new Map;_cacheKeysToIntegrities=new Map;_concurrentPrecaching;_precacheStrategy;_routes;_defaultHandlerMap;_catchHandler;_requestRules;constructor({precacheEntries:e,precacheOptions:t,skipWaiting:a=!1,importScripts:s,navigationPreload:r=!1,cacheId:i,clientsClaim:o=!1,runtimeCaching:l,offlineAnalyticsConfig:h,disableDevLogs:u=!1,fallbacks:d,requestRules:m}={}){const{precacheStrategyOptions:f,precacheRouteOptions:g,precacheMiscOptions:w}=((e,t={})=>{let{cacheName:a,plugins:s=[],fetchOptions:r,matchOptions:n,fallbackToNetwork:i,directoryIndex:o,ignoreURLParametersMatching:l,cleanURLs:h,urlManipulation:u,cleanupOutdatedCaches:d,concurrency:m=10,navigateFallback:f,navigateFallbackAllowlist:g,navigateFallbackDenylist:w}=t??{};return{precacheStrategyOptions:{cacheName:c(a),plugins:[...s,new eE({precacheController:e})],fetchOptions:r,matchOptions:n,fallbackToNetwork:i},precacheRouteOptions:{directoryIndex:o,ignoreURLParametersMatching:l,cleanURLs:h,urlManipulation:u},precacheMiscOptions:{cleanupOutdatedCaches:d,concurrency:m,navigateFallback:f,navigateFallbackAllowlist:g,navigateFallbackDenylist:w}}})(this,t);if(this._concurrentPrecaching=w.concurrency,this._precacheStrategy=new er(f),this._routes=new Map,this._defaultHandlerMap=new Map,this._requestRules=m,this.handleInstall=this.handleInstall.bind(this),this.handleActivate=this.handleActivate.bind(this),this.handleFetch=this.handleFetch.bind(this),this.handleCache=this.handleCache.bind(this),s&&s.length>0&&self.importScripts(...s),r&&self.registration?.navigationPreload&&self.addEventListener("activate",e=>{e.waitUntil(self.registration.navigationPreload.enable().then(()=>{}))}),void 0!==i&&(e=>{var t=e;for(let e of Object.keys(n))(e=>{let a=t[e];"string"==typeof a&&(n[e]=a)})(e)})({prefix:i}),a?self.skipWaiting():self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),o&&self.addEventListener("activate",()=>self.clients.claim()),e&&e.length>0&&this.addToPrecacheList(e),w.cleanupOutdatedCaches&&(e=>{self.addEventListener("activate",t=>{t.waitUntil(p(c(e)).then(e=>{}))})})(f.cacheName),this.registerRoute(new ev(this,g)),w.navigateFallback&&this.registerRoute(new en(this.createHandlerBoundToUrl(w.navigateFallback),{allowlist:w.navigateFallbackAllowlist,denylist:w.navigateFallbackDenylist})),void 0!==h&&("boolean"==typeof h?h&&ew({serwist:this}):ew({...h,serwist:this})),void 0!==l){if(void 0!==d){const e=new ep({fallbackUrls:d.entries,serwist:this});l.forEach(t=>{t.handler instanceof Z&&!t.handler.plugins.some(e=>"handlerDidError"in e)&&t.handler.plugins.push(e)})}for(const e of l)this.registerCapture(e.matcher,e.handler,e.method)}u&&(self.__WB_DISABLE_DEV_LOGS=!0)}get precacheStrategy(){return this._precacheStrategy}get routes(){return this._routes}addEventListeners(){self.addEventListener("install",this.handleInstall),self.addEventListener("activate",this.handleActivate),self.addEventListener("fetch",this.handleFetch),self.addEventListener("message",this.handleCache)}addToPrecacheList(e){let t=[];for(let a of e){"string"==typeof a?t.push(a):a&&!a.integrity&&void 0===a.revision&&t.push(a.url);let{cacheKey:e,url:s}=ec(a),r="string"!=typeof a&&a.revision?"reload":"default";if(this._urlsToCacheKeys.has(s)&&this._urlsToCacheKeys.get(s)!==e)throw new l("add-to-cache-list-conflicting-entries",{firstEntry:this._urlsToCacheKeys.get(s),secondEntry:e});if("string"!=typeof a&&a.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==a.integrity)throw new l("add-to-cache-list-conflicting-integrities",{url:s});this._cacheKeysToIntegrities.set(e,a.integrity)}this._urlsToCacheKeys.set(s,e),this._urlsToCacheModes.set(s,r)}t.length>0&&console.warn(`Serwist is precaching URLs without revision info: ${t.join(", ")} -This is generally NOT safe. Learn more at https://bit.ly/wb-precache`)}handleInstall(e){return this.registerRequestRules(e),y(e,async()=>{let t=new eo;this.precacheStrategy.plugins.push(t),await el(this._concurrentPrecaching,Array.from(this._urlsToCacheKeys.entries()),async([t,a])=>{let s=this._cacheKeysToIntegrities.get(a),r=this._urlsToCacheModes.get(t),n=new Request(t,{integrity:s,cache:r,credentials:"same-origin"});await Promise.all(this.precacheStrategy.handleAll({event:e,request:n,url:new URL(n.url),params:{cacheKey:a}}))});let{updatedURLs:a,notUpdatedURLs:s}=t;return{updatedURLs:a,notUpdatedURLs:s}})}async registerRequestRules(e){if(this._requestRules&&e?.addRoutes)try{await e.addRoutes(this._requestRules),this._requestRules=void 0}catch(e){throw e}}handleActivate(e){return y(e,async()=>{let e=await self.caches.open(this.precacheStrategy.cacheName),t=await e.keys(),a=new Set(this._urlsToCacheKeys.values()),s=[];for(let r of t)a.has(r.url)||(await e.delete(r),s.push(r.url));return{deletedCacheRequests:s}})}handleFetch(e){let{request:t}=e,a=this.handleRequest({request:t,event:e});a&&e.respondWith(a)}handleCache(e){if(e.data&&"CACHE_URLS"===e.data.type){let{payload:t}=e.data,a=Promise.all(t.urlsToCache.map(t=>{let a;return a="string"==typeof t?new Request(t):new Request(...t),this.handleRequest({request:a,event:e})}));e.waitUntil(a),e.ports?.[0]&&a.then(()=>e.ports[0].postMessage(!0))}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,ea(e))}setCatchHandler(e){this._catchHandler=ea(e)}registerCapture(e,t,a){let s=((e,t,a)=>{if("string"==typeof e){let s=new URL(e,location.href);return new es(({url:e})=>e.href===s.href,t,a)}if(e instanceof RegExp)return new ei(e,t,a);if("function"==typeof e)return new es(e,t,a);if(e instanceof es)return e;throw new l("unsupported-route-type",{moduleName:"serwist",funcName:"parseRoute",paramName:"capture"})})(e,t,a);return this.registerRoute(s),s}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 l("unregister-route-but-not-found-with-method",{method:e.method});let t=this._routes.get(e.method).indexOf(e);if(t>-1)this._routes.get(e.method).splice(t,1);else throw new l("unregister-route-route-not-registered")}getUrlsToPrecacheKeys(){return this._urlsToCacheKeys}getPrecachedUrls(){return[...this._urlsToCacheKeys.keys()]}getPrecacheKeyForUrl(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForPrecacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,a=this.getPrecacheKeyForUrl(t);if(a)return(await self.caches.open(this.precacheStrategy.cacheName)).match(a)}createHandlerBoundToUrl(e){let t=this.getPrecacheKeyForUrl(e);if(!t)throw new l("non-precached-url",{url:e});return a=>(a.request=new Request(e),a.params={cacheKey:t,...a.params},this.precacheStrategy.handle(a))}handleRequest({request:e,event:t}){let a,s=new URL(e.url,location.href);if(!s.protocol.startsWith("http"))return;let r=s.origin===location.origin,{params:n,route:i}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:s}),c=i?.handler,o=e.method;if(!c&&this._defaultHandlerMap.has(o)&&(c=this._defaultHandlerMap.get(o)),!c)return;try{a=c.handle({url:s,request:e,event:t,params:n})}catch(e){a=Promise.reject(e)}let l=i?.catchHandler;return a instanceof Promise&&(this._catchHandler||l)&&(a=a.catch(async a=>{if(l)try{return await l.handle({url:s,request:e,event:t,params:n})}catch(e){e instanceof Error&&(a=e)}if(this._catchHandler)return this._catchHandler.handle({url:s,request:e,event:t});throw a})),a}findMatchingRoute({url:e,sameOrigin:t,request:a,event:s}){for(let r of this._routes.get(a.method)||[]){let n,i=r.match({url:e,sameOrigin:t,request:a,event:s});if(i)return Array.isArray(n=i)&&0===n.length||i.constructor===Object&&0===Object.keys(i).length?n=void 0:"boolean"==typeof i&&(n=void 0),{route:r,params:n}}return{}}};let eq=[{matcher:/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,handler:new ex({cacheName:"google-fonts-webfonts",plugins:[new ef({maxEntries:4,maxAgeSeconds:31536e3,maxAgeFrom:"last-used"})]})},{matcher:/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,handler:new eb({cacheName:"google-fonts-stylesheets",plugins:[new ef({maxEntries:4,maxAgeSeconds:604800,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,handler:new eb({cacheName:"static-font-assets",plugins:[new ef({maxEntries:4,maxAgeSeconds:604800,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,handler:new eb({cacheName:"static-image-assets",plugins:[new ef({maxEntries:64,maxAgeSeconds:2592e3,maxAgeFrom:"last-used"})]})},{matcher:/\/_next\/static.+\.js$/i,handler:new ex({cacheName:"next-static-js-assets",plugins:[new ef({maxEntries:64,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\/_next\/image\?url=.+$/i,handler:new eb({cacheName:"next-image",plugins:[new ef({maxEntries:64,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:mp3|wav|ogg)$/i,handler:new ex({cacheName:"static-audio-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"}),new e_]})},{matcher:/\.(?:mp4|webm)$/i,handler:new ex({cacheName:"static-video-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"}),new e_]})},{matcher:/\.(?:js)$/i,handler:new eb({cacheName:"static-js-assets",plugins:[new ef({maxEntries:48,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:css|less)$/i,handler:new eb({cacheName:"static-style-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\/_next\/data\/.+\/.+\.json$/i,handler:new ee({cacheName:"next-data",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:json|xml|csv)$/i,handler:new ee({cacheName:"static-data-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\/api\/auth\/.*/,handler:new et({networkTimeoutSeconds:10})},{matcher:({sameOrigin:e,url:{pathname:t}})=>e&&t.startsWith("/api/"),method:"GET",handler:new ee({cacheName:"apis",plugins:[new ef({maxEntries:16,maxAgeSeconds:86400,maxAgeFrom:"last-used"})],networkTimeoutSeconds:10})},{matcher:({request:e,url:{pathname:t},sameOrigin:a})=>"1"===e.headers.get("RSC")&&"1"===e.headers.get("Next-Router-Prefetch")&&a&&!t.startsWith("/api/"),handler:new ee({cacheName:"pages-rsc-prefetch",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({request:e,url:{pathname:t},sameOrigin:a})=>"1"===e.headers.get("RSC")&&a&&!t.startsWith("/api/"),handler:new ee({cacheName:"pages-rsc",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({request:e,url:{pathname:t},sameOrigin:a})=>e.headers.get("Content-Type")?.includes("text/html")&&a&&!t.startsWith("/api/"),handler:new ee({cacheName:"pages",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({url:{pathname:e},sameOrigin:t})=>t&&!e.startsWith("/api/"),handler:new ee({cacheName:"others",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({sameOrigin:e})=>!e,handler:new ee({cacheName:"cross-origin",plugins:[new ef({maxEntries:32,maxAgeSeconds:3600})],networkTimeoutSeconds:10})},{matcher:/.*/i,method:"GET",handler:new et}];new eR({precacheEntries:[{'revision':'fb2db2f80495800c6e7f12c4471d9562','url':'/_next/static/Qs2gY1LeHn2Lj_Rcodhus/_buildManifest.js'},{'revision':'b6652df95db52feb4daf4eca35380933','url':'/_next/static/Qs2gY1LeHn2Lj_Rcodhus/_ssgManifest.js'},{'revision':null,'url':'/_next/static/chunks/3199-4a3557850e4b6905.js'},{'revision':null,'url':'/_next/static/chunks/3759-5d3f98d0fa0b9f96.js'},{'revision':null,'url':'/_next/static/chunks/5239-9df6f85b3ce4fcfc.js'},{'revision':null,'url':'/_next/static/chunks/8479-bc39a5eb65a9a9b8.js'},{'revision':null,'url':'/_next/static/chunks/87c73c54-f46fec743414da25.js'},{'revision':null,'url':'/_next/static/chunks/8916-8fae66d930cf17bb.js'},{'revision':null,'url':'/_next/static/chunks/app/_global-error/page-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/_not-found/page-4ba38dd60d12680e.js'},{'revision':null,'url':'/_next/static/chunks/app/achievements/page-400c045a202d4e32.js'},{'revision':null,'url':'/_next/static/chunks/app/api/achievements/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/actions/%5Bid%5D/undo/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/actions/recent/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/apply-template/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/items/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/items/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/quick-log/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/rest-day/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/todos/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/todos/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/catch-up/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/chat/knows/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/chat/sessions/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/chat/sessions/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/config/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/context/preview/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/health/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/learning/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/reset/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/%5Bid%5D/accept/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/%5Bid%5D/ignore/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/%5Bid%5D/reject/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/summary/rebuild/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/summary/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/models/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/suggestions/%5Bid%5D/dismiss/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/suggestions/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/templates/%5Bkey%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/templates/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/auth/login/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/books/%5Bid%5D/log-pages/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/books/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/books/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/cartographer/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/cron/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/dashboard/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/explorations/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/explorations/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/export/json/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/books/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/context/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/cover/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/progress/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/status/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/reflections/%5Bdate%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/reviews/%5BweekStart%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/settings/day-boundary/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/settings/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/stats/%5Bdomain%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/teacher/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/teacher/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/templates/%5Bid%5D/items/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/templates/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/templates/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/themes/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/cartographer/page-e4b8654b3c21d853.js'},{'revision':null,'url':'/_next/static/chunks/app/layout-ba1ea38fbfcd8c88.js'},{'revision':null,'url':'/_next/static/chunks/app/library/page-1cac926f1104fe58.js'},{'revision':null,'url':'/_next/static/chunks/app/login/page-5f636e39fc0fa1fb.js'},{'revision':null,'url':'/_next/static/chunks/app/mentor/page-730bec0dc6829005.js'},{'revision':null,'url':'/_next/static/chunks/app/page-0d30ebc423cd0f6f.js'},{'revision':null,'url':'/_next/static/chunks/app/review/page-6b65e1c5ef423974.js'},{'revision':null,'url':'/_next/static/chunks/app/settings/page-86d53bbd25eded66.js'},{'revision':null,'url':'/_next/static/chunks/app/statistics/page-27722c50b7ca4629.js'},{'revision':null,'url':'/_next/static/chunks/app/teacher/page-ccb6ea419b8acacc.js'},{'revision':null,'url':'/_next/static/chunks/app/yearly/page-bd1926b7a8dd7e73.js'},{'revision':null,'url':'/_next/static/chunks/framework-af3c63e39f557570.js'},{'revision':null,'url':'/_next/static/chunks/main-4a90bc78b0d3fc62.js'},{'revision':null,'url':'/_next/static/chunks/main-app-567e4578199091e8.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/app-error-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/forbidden-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/global-error-555d6023af128706.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/not-found-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/unauthorized-1006750767d18832.js'},{'revision':'846118c33b2c0e922d7b3a7676f81f6f','url':'/_next/static/chunks/polyfills-42372ed130431b0a.js'},{'revision':null,'url':'/_next/static/chunks/webpack-99360225e07f4440.js'},{'revision':null,'url':'/_next/static/css/ebf5306ae536a926.css'},{'revision':'d09f95206c3fa0bb9bd9fefabfd0ea71','url':'/file.svg'},{'revision':'2aaafa6a49b6563925fe440891e32717','url':'/globe.svg'},{'revision':'0927dc4135144aca169f3c770914dcbe','url':'/icons/icon.svg'},{'revision':'e8f86e44407fcbcd8f9748e1b3f67e95','url':'/manifest.json'},{'revision':'8e061864f388b47f33a1c3780831193e','url':'/next.svg'},{'revision':'c0af2f507b369b085b35ef4bbe3bcf1e','url':'/vercel.svg'},{'revision':'a2760511c65806022ad20adf74370ff3','url':'/window.svg'}],skipWaiting:!0,clientsClaim:!0,navigationPreload:!0,runtimeCaching:eq}).addEventListeners()})(); \ No newline at end of file +This is generally NOT safe. Learn more at https://bit.ly/wb-precache`)}handleInstall(e){return this.registerRequestRules(e),y(e,async()=>{let t=new eo;this.precacheStrategy.plugins.push(t),await el(this._concurrentPrecaching,Array.from(this._urlsToCacheKeys.entries()),async([t,a])=>{let s=this._cacheKeysToIntegrities.get(a),r=this._urlsToCacheModes.get(t),n=new Request(t,{integrity:s,cache:r,credentials:"same-origin"});await Promise.all(this.precacheStrategy.handleAll({event:e,request:n,url:new URL(n.url),params:{cacheKey:a}}))});let{updatedURLs:a,notUpdatedURLs:s}=t;return{updatedURLs:a,notUpdatedURLs:s}})}async registerRequestRules(e){if(this._requestRules&&e?.addRoutes)try{await e.addRoutes(this._requestRules),this._requestRules=void 0}catch(e){throw e}}handleActivate(e){return y(e,async()=>{let e=await self.caches.open(this.precacheStrategy.cacheName),t=await e.keys(),a=new Set(this._urlsToCacheKeys.values()),s=[];for(let r of t)a.has(r.url)||(await e.delete(r),s.push(r.url));return{deletedCacheRequests:s}})}handleFetch(e){let{request:t}=e,a=this.handleRequest({request:t,event:e});a&&e.respondWith(a)}handleCache(e){if(e.data&&"CACHE_URLS"===e.data.type){let{payload:t}=e.data,a=Promise.all(t.urlsToCache.map(t=>{let a;return a="string"==typeof t?new Request(t):new Request(...t),this.handleRequest({request:a,event:e})}));e.waitUntil(a),e.ports?.[0]&&a.then(()=>e.ports[0].postMessage(!0))}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,ea(e))}setCatchHandler(e){this._catchHandler=ea(e)}registerCapture(e,t,a){let s=((e,t,a)=>{if("string"==typeof e){let s=new URL(e,location.href);return new es(({url:e})=>e.href===s.href,t,a)}if(e instanceof RegExp)return new ei(e,t,a);if("function"==typeof e)return new es(e,t,a);if(e instanceof es)return e;throw new l("unsupported-route-type",{moduleName:"serwist",funcName:"parseRoute",paramName:"capture"})})(e,t,a);return this.registerRoute(s),s}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 l("unregister-route-but-not-found-with-method",{method:e.method});let t=this._routes.get(e.method).indexOf(e);if(t>-1)this._routes.get(e.method).splice(t,1);else throw new l("unregister-route-route-not-registered")}getUrlsToPrecacheKeys(){return this._urlsToCacheKeys}getPrecachedUrls(){return[...this._urlsToCacheKeys.keys()]}getPrecacheKeyForUrl(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForPrecacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,a=this.getPrecacheKeyForUrl(t);if(a)return(await self.caches.open(this.precacheStrategy.cacheName)).match(a)}createHandlerBoundToUrl(e){let t=this.getPrecacheKeyForUrl(e);if(!t)throw new l("non-precached-url",{url:e});return a=>(a.request=new Request(e),a.params={cacheKey:t,...a.params},this.precacheStrategy.handle(a))}handleRequest({request:e,event:t}){let a,s=new URL(e.url,location.href);if(!s.protocol.startsWith("http"))return;let r=s.origin===location.origin,{params:n,route:i}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:s}),c=i?.handler,o=e.method;if(!c&&this._defaultHandlerMap.has(o)&&(c=this._defaultHandlerMap.get(o)),!c)return;try{a=c.handle({url:s,request:e,event:t,params:n})}catch(e){a=Promise.reject(e)}let l=i?.catchHandler;return a instanceof Promise&&(this._catchHandler||l)&&(a=a.catch(async a=>{if(l)try{return await l.handle({url:s,request:e,event:t,params:n})}catch(e){e instanceof Error&&(a=e)}if(this._catchHandler)return this._catchHandler.handle({url:s,request:e,event:t});throw a})),a}findMatchingRoute({url:e,sameOrigin:t,request:a,event:s}){for(let r of this._routes.get(a.method)||[]){let n,i=r.match({url:e,sameOrigin:t,request:a,event:s});if(i)return Array.isArray(n=i)&&0===n.length||i.constructor===Object&&0===Object.keys(i).length?n=void 0:"boolean"==typeof i&&(n=void 0),{route:r,params:n}}return{}}};let eq=[{matcher:/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,handler:new ex({cacheName:"google-fonts-webfonts",plugins:[new ef({maxEntries:4,maxAgeSeconds:31536e3,maxAgeFrom:"last-used"})]})},{matcher:/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,handler:new eb({cacheName:"google-fonts-stylesheets",plugins:[new ef({maxEntries:4,maxAgeSeconds:604800,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,handler:new eb({cacheName:"static-font-assets",plugins:[new ef({maxEntries:4,maxAgeSeconds:604800,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,handler:new eb({cacheName:"static-image-assets",plugins:[new ef({maxEntries:64,maxAgeSeconds:2592e3,maxAgeFrom:"last-used"})]})},{matcher:/\/_next\/static.+\.js$/i,handler:new ex({cacheName:"next-static-js-assets",plugins:[new ef({maxEntries:64,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\/_next\/image\?url=.+$/i,handler:new eb({cacheName:"next-image",plugins:[new ef({maxEntries:64,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:mp3|wav|ogg)$/i,handler:new ex({cacheName:"static-audio-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"}),new e_]})},{matcher:/\.(?:mp4|webm)$/i,handler:new ex({cacheName:"static-video-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"}),new e_]})},{matcher:/\.(?:js)$/i,handler:new eb({cacheName:"static-js-assets",plugins:[new ef({maxEntries:48,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:css|less)$/i,handler:new eb({cacheName:"static-style-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\/_next\/data\/.+\/.+\.json$/i,handler:new ee({cacheName:"next-data",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\.(?:json|xml|csv)$/i,handler:new ee({cacheName:"static-data-assets",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400,maxAgeFrom:"last-used"})]})},{matcher:/\/api\/auth\/.*/,handler:new et({networkTimeoutSeconds:10})},{matcher:({sameOrigin:e,url:{pathname:t}})=>e&&t.startsWith("/api/"),method:"GET",handler:new ee({cacheName:"apis",plugins:[new ef({maxEntries:16,maxAgeSeconds:86400,maxAgeFrom:"last-used"})],networkTimeoutSeconds:10})},{matcher:({request:e,url:{pathname:t},sameOrigin:a})=>"1"===e.headers.get("RSC")&&"1"===e.headers.get("Next-Router-Prefetch")&&a&&!t.startsWith("/api/"),handler:new ee({cacheName:"pages-rsc-prefetch",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({request:e,url:{pathname:t},sameOrigin:a})=>"1"===e.headers.get("RSC")&&a&&!t.startsWith("/api/"),handler:new ee({cacheName:"pages-rsc",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({request:e,url:{pathname:t},sameOrigin:a})=>e.headers.get("Content-Type")?.includes("text/html")&&a&&!t.startsWith("/api/"),handler:new ee({cacheName:"pages",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({url:{pathname:e},sameOrigin:t})=>t&&!e.startsWith("/api/"),handler:new ee({cacheName:"others",plugins:[new ef({maxEntries:32,maxAgeSeconds:86400})]})},{matcher:({sameOrigin:e})=>!e,handler:new ee({cacheName:"cross-origin",plugins:[new ef({maxEntries:32,maxAgeSeconds:3600})],networkTimeoutSeconds:10})},{matcher:/.*/i,method:"GET",handler:new et}];new eR({precacheEntries:[{'revision':null,'url':'/_next/static/chunks/3199-4a3557850e4b6905.js'},{'revision':null,'url':'/_next/static/chunks/3759-5d3f98d0fa0b9f96.js'},{'revision':null,'url':'/_next/static/chunks/5239-9df6f85b3ce4fcfc.js'},{'revision':null,'url':'/_next/static/chunks/8479-7692f8880c4c2990.js'},{'revision':null,'url':'/_next/static/chunks/87c73c54-f46fec743414da25.js'},{'revision':null,'url':'/_next/static/chunks/8916-8fae66d930cf17bb.js'},{'revision':null,'url':'/_next/static/chunks/app/_global-error/page-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/_not-found/page-4ba38dd60d12680e.js'},{'revision':null,'url':'/_next/static/chunks/app/achievements/page-400c045a202d4e32.js'},{'revision':null,'url':'/_next/static/chunks/app/api/achievements/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/actions/%5Bid%5D/undo/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/actions/recent/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/apply-template/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/items/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/items/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/quick-log/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/rest-day/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/todos/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/%5Bdate%5D/todos/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/adventures/catch-up/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/chat/knows/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/chat/sessions/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/chat/sessions/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/config/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/context/preview/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/health/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/learning/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/reset/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/%5Bid%5D/accept/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/%5Bid%5D/ignore/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/%5Bid%5D/reject/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/suggestions/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/summary/rebuild/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/memory/summary/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/models/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/suggestions/%5Bid%5D/dismiss/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/suggestions/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/templates/%5Bkey%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/ai/templates/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/auth/login/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/books/%5Bid%5D/log-pages/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/books/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/books/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/cartographer/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/cron/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/dashboard/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/explorations/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/explorations/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/export/json/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/books/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/context/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/cover/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/progress/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/library/status/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/reflections/%5Bdate%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/reviews/%5BweekStart%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/settings/day-boundary/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/settings/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/stats/%5Bdomain%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/teacher/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/teacher/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/templates/%5Bid%5D/items/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/templates/%5Bid%5D/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/templates/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/api/themes/route-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/app/cartographer/page-e4b8654b3c21d853.js'},{'revision':null,'url':'/_next/static/chunks/app/layout-ba1ea38fbfcd8c88.js'},{'revision':null,'url':'/_next/static/chunks/app/library/page-1cac926f1104fe58.js'},{'revision':null,'url':'/_next/static/chunks/app/login/page-5f636e39fc0fa1fb.js'},{'revision':null,'url':'/_next/static/chunks/app/mentor/page-f34d5a926ba84c5f.js'},{'revision':null,'url':'/_next/static/chunks/app/page-5b6e9862a852a9e1.js'},{'revision':null,'url':'/_next/static/chunks/app/review/page-c79e740f3c0d7f0c.js'},{'revision':null,'url':'/_next/static/chunks/app/settings/page-934e9d4dcda30737.js'},{'revision':null,'url':'/_next/static/chunks/app/statistics/page-27722c50b7ca4629.js'},{'revision':null,'url':'/_next/static/chunks/app/teacher/page-ccb6ea419b8acacc.js'},{'revision':null,'url':'/_next/static/chunks/app/yearly/page-bd1926b7a8dd7e73.js'},{'revision':null,'url':'/_next/static/chunks/framework-af3c63e39f557570.js'},{'revision':null,'url':'/_next/static/chunks/main-4a90bc78b0d3fc62.js'},{'revision':null,'url':'/_next/static/chunks/main-app-567e4578199091e8.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/app-error-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/forbidden-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/global-error-555d6023af128706.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/not-found-1006750767d18832.js'},{'revision':null,'url':'/_next/static/chunks/next/dist/client/components/builtin/unauthorized-1006750767d18832.js'},{'revision':'846118c33b2c0e922d7b3a7676f81f6f','url':'/_next/static/chunks/polyfills-42372ed130431b0a.js'},{'revision':null,'url':'/_next/static/chunks/webpack-99360225e07f4440.js'},{'revision':null,'url':'/_next/static/css/8d14fbb5e0c187b9.css'},{'revision':'fb2db2f80495800c6e7f12c4471d9562','url':'/_next/static/uAVFOFW83j-Znj8sxuLaW/_buildManifest.js'},{'revision':'b6652df95db52feb4daf4eca35380933','url':'/_next/static/uAVFOFW83j-Znj8sxuLaW/_ssgManifest.js'},{'revision':'d09f95206c3fa0bb9bd9fefabfd0ea71','url':'/file.svg'},{'revision':'2aaafa6a49b6563925fe440891e32717','url':'/globe.svg'},{'revision':'0927dc4135144aca169f3c770914dcbe','url':'/icons/icon.svg'},{'revision':'e8f86e44407fcbcd8f9748e1b3f67e95','url':'/manifest.json'},{'revision':'8e061864f388b47f33a1c3780831193e','url':'/next.svg'},{'revision':'c0af2f507b369b085b35ef4bbe3bcf1e','url':'/vercel.svg'},{'revision':'a2760511c65806022ad20adf74370ff3','url':'/window.svg'}],skipWaiting:!0,clientsClaim:!0,navigationPreload:!0,runtimeCaching:eq}).addEventListeners()})(); \ No newline at end of file diff --git a/apps/web/src/lib/services/ai-context.test.ts b/apps/web/src/lib/services/ai-context.test.ts index 6c9e1dc..f064cec 100755 --- a/apps/web/src/lib/services/ai-context.test.ts +++ b/apps/web/src/lib/services/ai-context.test.ts @@ -9,6 +9,7 @@ describe("formatContextForPrompt", () => { memoryIds: [], activeDay: { dayMode: "low_energy", isBackfilled: false }, recentActivity: "recent", + recentLogDetails: "", featureSlice: "", tokenEstimate: 100, layers: { memories: "" }, @@ -24,10 +25,26 @@ describe("formatContextForPrompt", () => { memoryIds: ["1"], activeDay: { isBackfilled: true, dayMode: "normal" }, recentActivity: "", + recentLogDetails: "", featureSlice: "", tokenEstimate: 50, layers: { memories: "[likes] T: C" }, }); expect(text).toContain("backfilled"); }); + + it("includes recent log details", () => { + const text = formatContextForPrompt({ + profileSummary: "", + memories: [], + memoryIds: [], + activeDay: { dayMode: "normal" }, + recentActivity: "", + recentLogDetails: "2026-06-27: Items: Prayer: 3/5 checked (partial)", + featureSlice: "", + tokenEstimate: 50, + layers: { memories: "" }, + }); + expect(text).toContain("Prayer: 3/5"); + }); }); diff --git a/apps/web/src/lib/services/ai-context.ts b/apps/web/src/lib/services/ai-context.ts index 793a034..6e0a5af 100755 --- a/apps/web/src/lib/services/ai-context.ts +++ b/apps/web/src/lib/services/ai-context.ts @@ -1,5 +1,5 @@ import { format, subDays } from "date-fns"; -import type { MemoryCategory, DayMode } from "@adventureos/shared"; +import type { MemoryCategory } from "@adventureos/shared"; import { MEMORY_CATEGORIES } from "@adventureos/shared"; import { requireUser } from "./user"; import { getDailyAdventure, buildDaySnapshot } from "./adventure"; @@ -7,7 +7,7 @@ import { getReflection } from "./reflection"; import { getProfileSummary, listMemories, markMemoriesUsed } from "./ai-memory"; import { getLogicalToday } from "../dates"; import { getDayBoundaryHour } from "./day-boundary"; -import { db, explorations, weeklyReviews, aiContextLogs } from "../db"; +import { db, explorations, weeklyReviews, aiContextLogs, readingLogs, books } from "../db"; import { and, eq, desc } from "drizzle-orm"; import { weekStartString } from "../dates"; @@ -43,6 +43,7 @@ export type BuiltContext = { memoryIds: string[]; activeDay: Record | null; recentActivity: string; + recentLogDetails: string; featureSlice: string; tokenEstimate: number; layers: Record; @@ -81,6 +82,162 @@ function categoriesFromMessage(message: string): Set { return cats; } +function unique(items: T[]): T[] { + return [...new Set(items)]; +} + +function contextDates(activeDate: string, message: string): string[] { + const lower = message.toLowerCase(); + const dates = [activeDate]; + + for (let i = 1; i < 7; i++) { + dates.push(format(subDays(new Date(activeDate), i), "yyyy-MM-dd")); + } + + if (lower.includes("today")) dates.unshift(activeDate); + if (lower.includes("yesterday")) { + dates.unshift(format(subDays(new Date(activeDate), 1), "yyyy-MM-dd")); + } + + const explicitDates = message.match(/\b\d{4}-\d{2}-\d{2}\b/g) ?? []; + dates.unshift(...explicitDates); + + return unique(dates).slice(0, 10); +} + +function summarizeItemValue(item: { + type: string; + label: string; + state: string; + value: Record; +}): string | null { + if (item.type === "checklist") { + const checks = (item.value?.checks as boolean[]) ?? []; + const checked = checks.filter(Boolean).length; + return `${checked}/${checks.length} checked (${item.state})`; + } + + if (item.type === "duration") { + const hours = Number(item.value?.hours ?? 0); + return `${hours.toFixed(1)}h (${item.state})`; + } + + if (item.type === "reading") { + const pages = Number(item.value?.pages ?? 0); + return pages > 0 ? `${pages} pages (${item.state})` : `0 pages (${item.state})`; + } + + if (item.type === "note") { + const note = String(item.value?.note ?? "").trim(); + return note ? truncate(note, 220) : null; + } + + if (item.type === "checkbox" || item.type === "timeblock") { + return item.state === "done" ? "done" : "not done"; + } + + return Object.keys(item.value ?? {}).length > 0 ? JSON.stringify(item.value) : item.state; +} + +function shouldIncludeItem(item: { + type: string; + state: string; + value: Record; +}): boolean { + if (item.type === "checklist") return true; + if (item.type === "note") return Boolean(String(item.value?.note ?? "").trim()); + return item.state !== "blank" || Object.keys(item.value ?? {}).length > 0; +} + +export async function buildRecentLogDetails( + userId: string, + activeDate: string, + message = "" +): Promise { + const lines: string[] = []; + + for (const date of contextDates(activeDate, message)) { + const { adventure, items, todos } = await getDailyAdventure(userId, date); + const reflection = await getReflection(userId, date); + const dayLines: string[] = []; + + const itemLines = items + .filter((i) => i.enabled && shouldIncludeItem({ + type: i.type, + state: i.state, + value: i.value as Record, + })) + .map((i) => { + const summary = summarizeItemValue({ + type: i.type, + label: i.label, + state: i.state, + value: i.value as Record, + }); + return summary ? `${i.label}: ${summary}` : null; + }) + .filter(Boolean); + + if (itemLines.length > 0) dayLines.push(`Items: ${itemLines.join("; ")}`); + + if (todos.length > 0) { + const done = todos.filter((t) => t.done).map((t) => t.label); + const open = todos.filter((t) => !t.done).map((t) => t.label); + dayLines.push( + `Todos: ${done.length}/${todos.length} done` + + (done.length ? `; done: ${done.join(", ")}` : "") + + (open.length ? `; open: ${open.join(", ")}` : "") + ); + } + + if (reflection) { + const reflectionParts = [ + reflection.wentWell ? `went well: ${truncate(reflection.wentWell, 180)}` : "", + reflection.learned ? `learned: ${truncate(reflection.learned, 180)}` : "", + reflection.improveTomorrow + ? `improve tomorrow: ${truncate(reflection.improveTomorrow, 180)}` + : "", + ].filter(Boolean); + if (reflectionParts.length > 0) dayLines.push(`Reflection: ${reflectionParts.join("; ")}`); + } + + const reading = await db + .select({ + title: books.title, + author: books.author, + pagesRead: readingLogs.pagesRead, + note: readingLogs.note, + }) + .from(readingLogs) + .innerJoin(books, eq(readingLogs.bookId, books.id)) + .where(and(eq(books.userId, userId), eq(readingLogs.date, date))); + + if (reading.length > 0) { + dayLines.push( + `Reading logs: ${reading + .map( + (r) => + `${r.title}${r.author ? ` by ${r.author}` : ""}: ${r.pagesRead}p` + + (r.note ? `, note: ${truncate(r.note, 140)}` : "") + ) + .join("; ")}` + ); + } + + if (dayLines.length > 0 || adventure.isRestDay || adventure.isBackfilled) { + const flags = [ + adventure.dayMode && adventure.dayMode !== "normal" ? `mode=${adventure.dayMode}` : "", + adventure.isRestDay ? "rest day" : "", + adventure.isBackfilled ? "backfilled" : "", + adventure.loggedAt ? `logged=${adventure.loggedAt.toISOString()}` : "", + ].filter(Boolean); + lines.push(`${date}${flags.length ? ` (${flags.join(", ")})` : ""}: ${dayLines.join(" | ")}`); + } + } + + return truncate(lines.join("\n"), 3500); +} + export async function buildMentorContext( userId: string, opts: MentorContextOptions = {} @@ -112,14 +269,17 @@ export async function buildMentorContext( let activeDay: Record | null = null; try { - const { adventure, items } = await getDailyAdventure(userId, activeDate); + const { adventure, items, todos } = await getDailyAdventure(userId, activeDate); activeDay = { date: activeDate, dayMode: adventure.dayMode ?? "normal", isRestDay: adventure.isRestDay, isBackfilled: adventure.isBackfilled, + loggedAt: adventure.loggedAt?.toISOString() ?? null, itemsLogged: items.filter((i) => i.state !== "blank").length, itemCount: items.filter((i) => i.enabled && i.type !== "note").length, + todosDone: todos.filter((t) => t.done).length, + todoCount: todos.length, }; } catch { activeDay = { date: activeDate }; @@ -136,6 +296,7 @@ export async function buildMentorContext( ); } const recentActivity = truncate(digestParts.join("\n"), 800); + const recentLogDetails = await buildRecentLogDetails(userId, activeDate, message); let featureSlice = ""; if (opts.feature === "teacher" && opts.topic) { @@ -154,6 +315,7 @@ export async function buildMentorContext( memories: memories.map((m) => `[${m.category}] ${m.title}: ${m.content}`).join("\n"), activeDay: JSON.stringify(activeDay), recentActivity, + recentLogDetails, featureSlice, }; @@ -179,6 +341,7 @@ export async function buildMentorContext( memoryIds, activeDay, recentActivity, + recentLogDetails, featureSlice, tokenEstimate, layers, @@ -265,6 +428,7 @@ export function formatContextForPrompt(ctx: BuiltContext): string { `Today: ${ctx.layers.activeDay}`, dayNote, `Recent:\n${ctx.recentActivity}`, + ctx.recentLogDetails ? `Recent log details:\n${ctx.recentLogDetails}` : "", ctx.featureSlice, ] .filter(Boolean) diff --git a/apps/web/src/lib/services/ai.ts b/apps/web/src/lib/services/ai.ts index 791030a..c64ee26 100755 --- a/apps/web/src/lib/services/ai.ts +++ b/apps/web/src/lib/services/ai.ts @@ -526,6 +526,7 @@ export async function generateChatReply( `User: ${input.userMessage}`, input.memoryAction ? `Application memoryAction result: ${input.memoryAction}` : "", "Memory guardrail: You must not claim that a memory has been saved, added, approved, rejected, deleted, or changed unless the application memoryAction result confirms it. If no memoryAction result confirms persistence, do not imply that memory persistence happened.", + "Log access: If the user asks about notes, prayers, todos, reading, reflections, or other logged activity, answer from the Personal context records. If a requested date or log entry is not present in context, say that you do not have that record in the current context instead of guessing.", "If the user asks whether you can learn about them, explain that AdventureOS can suggest memories from goals, preferences, routines, worries, and direct remember requests; the user can review, edit, accept, reject, or ignore suggestions before they become saved memory.", "Respond as the mentor in plain text (no JSON). Keep it concise for a local model.", ]