1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["js/fetchmetak7U1zgO7.js","js/cjs-helpersC4iS2aBk.js","js/constantsDW26WJ6H.js","js/OperationQueueKzEpmh-u.js","js/item-name.utilsBH3paGZr.js","js/dexie2jmnBxhj.js","js/chunkReloadRecoveryrjuMb-b8.js","js/vue-runtimeBHGad_ZB.js","js/bootstrap-vue-nextDXY4qsO1.js","assets/bootstrap-vue-nexthA7rx8St.css","assets/chunkReloadRecoveryUbLNi8xK.css","js/item.typesx7Q7rrX9.js","js/content.typesyje91KzF.js","js/extraction.pure.utilsDQPW8yIh.js","js/url.utils3SlYVg-c.js","js/product-metadata.utilsCPJCtBKQ.js","js/pdf-metadata.utilsBj6tdlcd.js"])))=>i.map(i=>d[i]); 2var Rt=Object.defineProperty;var Ct=(p,e,t)=>e in p?Rt(p,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):p[e]=t;var k=(p,e,t)=>Ct(p,typeof e!="symbol"?e+"":e,t);import{T as Se,d5 as yt,d6 as Ut,d7 as xt,af as _t,f as h,b as oe,a as bt,e as se,d as Fe,c as D,V,O as R,N as Ee,U as J,R as O,C as Ft,am as Ve,d8 as Et,cE as Be,d4 as At,bV as Tt}from"./chunkReloadRecoveryrjuMb-b8.js";import{c as tt,P as Ke,e as kt,d as Mt,f as Ne}from"./noteAttachmentDId5R_kp.js";import{Q as It,ax as Lt,C as ge,D as S,U as ye,E as Ce,aw as Dt,a4 as Pt,ad as we,an as st,H as N,ay as nt,az as ee,Z as $}from"./OperationQueueKzEpmh-u.js";import{y as it,z as Bt,A as Kt,d as Nt,B as Ot}from"./file_utilsBvAXo0vA.js";import{R as G,C as M,d as xe,k as Ie,g as ae,j as qt,h as Oe}from"./item-name.utilsBH3paGZr.js";import{n as Wt,m as zt}from"./extraction.pure.utilsDQPW8yIh.js";import{S as Ht,B as $t,I as jt}from"./constantsDW26WJ6H.js";import{F as Ae}from"./api-typesD1zIcSfT.js";import{u as Vt,l as Yt,m as Gt}from"./url.utils3SlYVg-c.js";import{S as Qt,m as Jt,n as Xt}from"./freshSignInv8N2vL5e.js";import{i as Zt}from"./textEmbeddingUtilsBRNkRshv.js";import{c as at}from"./feedback.utilscwcZGi10.js";import{I as rt,P as me,g as es}from"./item.typesx7Q7rrX9.js";import{b as ts,s as ss,Q as gt,R as ns,w as is,S as ot,r as ct}from"./content.typesyje91KzF.js";import{m as as}from"./feedDiscoveryCsjZq3pR.js";import{a as rs}from"./itemImageSourcesCubmTdva.js";import{m as os}from"./search-provider.utilsBiOzVtNa.js";import{s as cs}from"./statusFacetsB0tsuUpJ.js";import{isRolloutCapReady as ls}from"./rolloutCapsBJsLLLO7.js";const de=class de{constructor(){k(this,"signoutCallbacks",[])}static get instance(){return de._staticInstance||(de._staticInstance=new de),de._staticInstance}async addSignoutCallback(e){this.signoutCallbacks.push(e)}async runSignoutCallbacks(){for(const e of this.signoutCallbacks)await e()}};k(de,"_staticInstance",null);let ve=de;const ds=[Se.strictnessPresetId,Se.contentFilters];function us(){const p=yt(null,!1,!1);return{advancedPrefs:{},contentFilters:p.contentFilters,selectedPresetId:p.presetId,blockedUrlPatterns:[],serverDeepLookupEnabled:!1,adLoadAnalysisEnabled:!1,hasExplicitImageCensoringPreference:!1,localAuthorityEstablished:!1,source:"remote"}}const qe=new Map;function fs(p,e,t){return[p._id,p.type??"",p.dob??"",t?"force":"cache",[...e].sort().join(",")].join("::")}async function hs(p){if(!p.user)return us();const e=p.user,t=p.forceRefresh===!0,s=Array.from(new Set([...ds,...p.additionalKeys||[]])),n=fs(e,s,t),i=qe.get(n);if(i)return await i;const a=ps(e,s,t);qe.set(n,a);try{return await a}finally{qe.delete(n)}}async function ps(p,e,t){const s={userId:p._id,keys:e};let n=null,i="remote";if(!t){const r=await Lt(s);r!=null&&r.authorityEstablished&&(n=r.requestedPrefs,i="local-authoritative")}n||(n=await It("/user/prefs/get",s,{forceRefresh:t}),i="remote");const a=yt(n,p.type==="restricted",p.type==="restricted"||p.type!=="admin"&&Ut(p.dob,18)===!0);return{advancedPrefs:n,contentFilters:a.contentFilters,selectedPresetId:a.presetId,blockedUrlPatterns:_t(n==null?void 0:n[Se.blockedUrlPatterns]),serverDeepLookupEnabled:(n==null?void 0:n[Se.serverDeepLookupEnabled])===!0,adLoadAnalysisEnabled:(n==null?void 0:n[Se.adLoadAnalysisEnabled])===!0,hasExplicitImageCensoringPreference:xt(n),localAuthorityEstablished:i==="local-authoritative",source:i}}const ws=8e3;async function lt(p,e){if(p!=null&&p._id)try{await Promise.race([hs({user:p,forceRefresh:!0}),new Promise(t=>setTimeout(t,ws))]),h("[prefs-warm] content-filter prefs warmed",{reason:e,userId:p._id})}catch(t){h("[prefs-warm] warmContentFilterPrefs failed",{reason:e,error:t})}}const We="kindredRemovalAlert";function mt(){var e;const p=(e=globalThis.chrome)==null?void 0:e.runtime;return typeof(p==null?void 0:p.setUninstallURL)=="function"?p:null}function ys(){return D.appType==="extension"&&!D.browser_mode&&!D.isMobileApp&&mt()!=null}function Is(p,e){const t=new URLSearchParams({u:e.u,c:e.c,s:e.s});return`${p.replace(/\/+$/,"")}/extension/removed?${t}`}async function dt(p){var e;try{await((e=mt())==null?void 0:e.setUninstallURL(p))}catch(t){console.warn("[removal-alert] setUninstallURL failed",t)}}
2async function gs(p){var t;if(!ys()||!(p!=null&&p._id))return;const e=await oe(We);if(p.type===ge.restricted){let s=null;try{s=((t=await S("/extension/removalAlert/register",{}))==null?void 0:t.link)??null}catch(a){console.warn("[removal-alert] register failed",a);return}const{apiURL:n}=await bt();if(!s||!n)return;const i=Is(n,s);await dt(i),await se(We,{userId:p._id,accountId:p.accountId||"",url:i});return}e!=null&&e.accountId&&e.accountId===p.accountId||(await dt(""),e&&await Fe(We))}const Ye="fullResetLog",ms=20;function Ss(p,e,t,s){const n=[];return s&&n.push("forceFullReset"),p!=null&&p.lastFullReset||n.push("noLastFullReset"),(p==null?void 0:p.currentUserId)!=e&&n.push(`userChanged:${(p==null?void 0:p.currentUserId)??"none"}->${e}`),(p==null?void 0:p.indexVersion)!=t&&n.push("indexVersionChanged"),p!=null&&p.fullResetComplete||n.push("fullResetIncomplete"),p&&typeof p.indexInfoData=="object"&&p.indexInfoData!==null&&n.push("malformedIndexInfoRecord"),n}async function _e(p){try{h("[SIndex] FULL RESET reason:",p);const e=await oe(Ye)||[],t=Array.isArray(e)?e:[];t.push(p),await se(Ye,t.slice(-ms))}catch(e){h("[SIndex] failed to record full reset event (non-fatal)",e)}}async function ln(){try{const p=await oe(Ye);return Array.isArray(p)?p:[]}catch{return[]}}const te=1,j=class j{constructor(e,t){this.userService=e,this.encryptionService=t}static get instance(){return j._staticInstance||(j._staticInstance=new j(ye.instance,Ce.instance)),j._staticInstance}async getDataIndexId(e=null){const t=await this.userService.getCurrentUser();return t.localUser===!0?t.accountId:e||t._id}async getDataIndex(e=null){const t=await this.getDataIndexId(e);return Qt.getInstance(t)}async getDataIndexStatus(e=null){const t=await this.getDataIndexId(e);return Jt.getInstance(t)}async handleUpdateIndexRequest(e={}){const{refreshUser:t=!1,forceFullReset:s=!1,overrideExistingRun:n=!1,forcePartialUpdate:i=!1,userId:a,onBusy:r}=e;a?await this.updateDataIndexForUser(a,s,n,i,{onBusy:r}):await this.updateDataIndex(s,t,n,i,{onBusy:r})}async _withIndexLock(e,t,s="wait"){const n=await this.getDataIndexId(e),i=Dt.getMutex(`sindex_${n}`);if(s==="skip"){if(!i.tryAcquire())return h("[SIndex] index update already running, skipping",{idxKey:n}),!1}else await i.acquire();try{return await t()}finally{i.release()}}async updateDataIndex(e=!1,t=!1,s=!1,n=!1,i={}){h("[SIndex] updateDataIndex:",e,t,s,n);try{if(!await V.instance.isActive())return!1;const a=await this.userService.getCurrentUser(t||e);return a?await this._withIndexLock(a._id,()=>this._updateDataIndex(a,e,s,n),i.onBusy):(await V.instance.isActive()&&await V.instance.reset(),!1)}catch(a){return console.error("Error updating index",a),!1}}async updateDataIndexForUser(e,t=!1,s=!1,n=!1,i={}){try{if(!await V.instance.isActive())return!1;const a=await this.userService.getUserById(e);return a?await this._withIndexLock(a._id,()=>this._updateDataIndex(a,t,s,n),i.onBusy):(await V.instance.isActive()&&(h("No Current user, resetting connection"),await V.instance.reset()),!1)}catch(a){return console.error("Error updating index",a),!1}}async isLibraryIndexHydrated(e=null){try{let t=e;if(!t){const n=await this.userService.getCurrentUser();t=(n==null?void 0:n._id)||null}if(!t)return!1;const s=await oe(`indexInfo_${t}`)||null;return s?s.fullResetComplete===!0&&!!s.lastFullReset&&s.currentUserId===t&&s.indexVersion===te:!1}catch(t){return h("[SIndex] isLibraryIndexHydrated check failed",t),!0}}async _updateDataIndex(e,t=!1,s=!1,n=!1){if(await R())return h("[SIndex] Device-only Mode enabled, building indices from local storage"),await this._updateDataIndexLocal(e,t,s,n);h("[SIndex] Running index update request, forceFullReset=",t,e);let i=t;const a=e.updatedAt?new Date(e.updatedAt):new Date,r=`indexInfo_${e._id}`,c=await oe(r)||{},o={lastUpdate:void 0,lastRevision:void 0,lastFullReset:void 0,updateCount:0,currentUserId:void 0,indexVersion:void 0,fullResetComplete:!1,...c},l=Ss(c,e._id,te,t);l.length>0&&(i=!0,await _e({at:new Date().toJSON(),userId:e._id,source:t?"forced":"client",reasons:l,indexInfoSnapshot:c}));const d=o!=null&&o.lastUpdate&&!i?new Date(o==null?void 0:o.lastUpdate):null,u=typeof e.syncRevision=="number"?e.syncRevision:null,f=typeof(o==null?void 0:o.lastRevision)=="number"&&!i?o.lastRevision:null,y=u!==null&&f!==null?f>=u:!!d&&d>=a;if(!n&&!i&&y){h("[SIndex] update not needed:",{uid:e._id,localLastUpdate:d,actualLastUpdate:a,needFullreset:i,indexInfo:o,currentTime:new Date});try{await this.updateContextsIndex(!1,e._id),await this.updatePluginsIndex(!1,e._id)}catch(E){h("[SIndex] ensure context/plugin indices failed (non-fatal)",E)}return!1}if(h("[SIndex] update request",{localLastUpdate:d,actualLastUpdate:a,needFullreset:i,indexInfo:o}),t)await Fe(j.fullSyncProgressId(e._id));else if(i){const E=await this._tryResumeChunkedFullSync(e,s);if(E!==null)return E}const m=typeof(o==null?void 0:o.lastRevision)=="number"&&!i?o.lastRevision:null,w=await this._fetchChangeLog({userId:e._id,lastUpdate:d,lastRevision:m});if(Array.isArray(w.chunkedItemIds))return i||await _e({at:new Date().toJSON(),userId:e._id,source:"server",reasons:[w.fullResetReason||"serverForcedFullReset"]}),await(await this.getDataIndexStatus(e._id)).isBuilding()&&!s?(h("[SIndex] Index is already building, skipping chunked full sync"),!1):await this._runChunkedFullSync(e,{itemIds:w.chunkedItemIds,pagesDone:0,startedAt:new Date().toJSON(),serverLastUpdate:a.toJSON(),serverRevision:w.revision,indexVersion:te});const{fullReset:I,updatedItems:U,removedItemIds:F,totalUpdates:_}=w;h("[SIndex] Total Updates in batch:",{totalUpdates:_,fullReset:I,updatedItems:U,removedItemIds:F});const C=i||I;if(h("[SIndex] isFullReset = ",C),I&&!i&&await _e({at:new Date().toJSON(),userId:e._id,source:"server",reasons:[w.fullResetReason||"serverForcedFullReset"]}),_==0&&!I){h("[SIndex] No updates, skipping");try{await this.updateContextsIndex(!1,e._id),await this.updatePluginsIndex(!1,e._id)}catch(E){h("[SIndex] ensure context/plugin indices failed (non-fatal)",E)}return o.lastUpdate=a.toJSON(),typeof w.revision=="number"&&(o.lastRevision=w.revision),o.updateCount=o.updateCount+1,o.currentUserId=e._id,o.indexVersion=te,await se(r,o),!1}const A=await this.getDataIndex(e._id);if(await(await this.getDataIndexStatus(e._id)).isBuilding())if(s)h("[SIndex] Index is building, but overrideExistingRun is true, so continuing");else return h("[SIndex] Index is already building, skipping update"),!1;if(C&&await se(r,{...o,fullResetComplete:!1}),h("[SIndex] Starting Index Update",{isFullReset:C,updatedItems:U,removedItemIds:F}),await A.updateStores({updatedItems:U,removedItemIds:F},C)){try{await this.updatePluginsIndex(!1,e._id)}catch(E){h("[SIndex] post-update plugins index failed (non-fatal)",E)}return o.lastUpdate=a.toJSON(),typeof w.revision=="number"&&(o.lastRevision=w.revision),o.updateCount=o.updateCount+1,o.currentUserId=e._id,o.indexVersion=te,C&&(o.fullResetComplete=!0,o.lastFullReset=a.toJSON(),o.updateCount=0),h(`[SIndex] reset isFullReset=${C} complete index`,o),await se(r,o),!0}else return h("[SIndex] update failed"),!1}async _updateDataIndexLocal(e,t=!1,s=!1,n=!1){const i=`indexInfo_${e._id}`,r={lastUpdate:void 0,lastFullReset:void 0,updateCount:0,currentUserId:void 0,indexVersion:void 0,fullResetComplete:!1,...await oe(i)||{}};if(!(t||n||!r.lastFullReset||r.currentUserId!==e._id||r.indexVersion!==te||!r.fullResetComplete)&&r.fullResetComplete)return h("[SIndex] Local indices already built"),!1;n&&!t&&h("[SIndex] Local partial update requested, rebuilding indices from local storage");const o=await this.getDataIndex(e._id);if(await(await this.getDataIndexStatus(e._id)).isBuilding()&&!s)return h("[SIndex] Index is already building, skipping update"),!1;h("[SIndex] Building local indices from IndexedDB");const d=await o.itemDataStore.listAll();if(h("[SIndex] Found items in local storage:",d.length),await o.updateStores({updatedItems:d,removedItemIds:[]},!0)){const f=new Date().toJSON();return r.lastUpdate=f,r.lastFullReset=f,r.updateCount=0,r.currentUserId=e._id,r.indexVersion=te,r.fullResetComplete=!0,await se(i,r),h("[SIndex] Local indices built successfully"),!0}return h("[SIndex] Failed to build local indices"),!1}async _fetchChangeLog(e){if(await R())return h("[SIndex] _fetchChangeLog called in device-
2only mode (should not happen)"),{fullReset:!1,updatedItems:[],removedItemIds:[],totalUpdates:0};const t=await this.encryptionService.remoteRequestEncryptionWrapper("/sync/update",{userId:e.userId,lastUpdate:e.lastUpdate,...typeof e.lastRevision=="number"?{lastRevision:e.lastRevision}:{},chunked:!0});if(!t||typeof t!="object")throw new Error("[SIndex] /sync/update returned an empty changelog response");if(Array.isArray(t.chunkedItemIds))return{fullReset:!0,updatedItems:[],removedItemIds:[],totalUpdates:t.chunkedItemIds.length,chunkedItemIds:t.chunkedItemIds,revision:typeof t.revision=="number"?t.revision:void 0};const s=t.fullReset===!0,n=Array.isArray(t.updatedItems)?t.updatedItems:[],i=Array.isArray(t.removedItemIds)?t.removedItemIds:[],a=typeof t.totalUpdates=="number"?t.totalUpdates:n.length+i.length,r=n.filter(j._isItemReadable);return{fullReset:s,updatedItems:r,removedItemIds:i,totalUpdates:a,revision:typeof t.revision=="number"?t.revision:void 0}}static _isItemReadable(e){var t,s;return!!((t=e==null?void 0:e.details)!=null&&t.decrypted)||!((s=e==null?void 0:e.details)!=null&&s.encrypted)}static fullSyncProgressId(e){return`fullSyncProgress_${e}`}async _tryResumeChunkedFullSync(e,t){const s=j.fullSyncProgressId(e._id),n=await oe(s);if(!n||!Array.isArray(n.itemIds)||typeof n.pagesDone!="number")return null;const i=Date.now()-new Date(n.startedAt).getTime();return n.indexVersion!==te||!(i>=0&&i<j.FULL_SYNC_RESUME_MAX_AGE_MS)?(await Fe(s),null):await(await this.getDataIndexStatus(e._id)).isBuilding()&&!t?(h("[SIndex] Index is already building, skipping resume"),!1):(await _e({at:new Date().toJSON(),userId:e._id,source:"client",reasons:[`resumedChunkedFullSync:page${n.pagesDone}`]}),await this._runChunkedFullSync(e,n))}async _runChunkedFullSync(e,t){const s=`indexInfo_${e._id}`,n=j.fullSyncProgressId(e._id),i=await this.getDataIndex(e._id);if(t.pagesDone>0){if(!await i.beginFullBuild({resume:!0})&&(h("[SIndex] staged full-build data missing, restarting chunked full sync from page 0"),t={...t,pagesDone:0},!await i.beginFullBuild({resume:!1})))return!1}else if(!await i.beginFullBuild({resume:!1}))return!1;const a=Zt(t.itemIds,Ht);t.pagesDone===0&&(await se(s,{currentUserId:e._id,indexVersion:te,fullResetComplete:!1}),await se(n,t)),h("[SIndex] chunked full sync",{pages:a.length,resumeFromPage:t.pagesDone});let r=!1;try{for(let c=t.pagesDone;c<a.length;c+=j.SYNC_FETCH_CONCURRENCY){const o=a.slice(c,c+j.SYNC_FETCH_CONCURRENCY),d=(await Promise.all(o.map(y=>this._fetchChunkedPage(e._id,y)))).flat();if(!await i.applyFullBuildChunk({updatedItems:d,removedItemIds:[]}))return h("[SIndex] chunked full sync wave failed",{pagesDone:c}),!1;const f=Math.min(c+o.length,a.length);await se(n,{...t,pagesDone:f}),h("[SIndex] chunked sync progress",{pagesDone:f,pages:a.length})}if(!await i.commitFullBuild(t.itemIds,{sweepOlderThan:t.startedAt}))return h("[SIndex] chunked full sync commit failed"),!1;r=!0}finally{r||i.pauseFullBuild()}try{await this.updateContextsIndex(!1,e._id),await this.updatePluginsIndex(!1,e._id)}catch(c){h("[SIndex] post-update plugins index failed (non-fatal)",c)}return await se(s,{lastUpdate:t.serverLastUpdate,...typeof t.serverRevision=="number"?{lastRevision:t.serverRevision}:{},lastFullReset:t.serverLastUpdate,updateCount:0,currentUserId:e._id,indexVersion:te,fullResetComplete:!0}),await Fe(n),!0}async _fetchChunkedPage(e,t){const s=await this.encryptionService.remoteRequestEncryptionWrapper("/sync/update",{userId:e,fetchItemIds:t});if(!s||s.success===!1||!Array.isArray(s.updatedItems)){const n=(s==null?void 0:s.errorType)||(s==null?void 0:s.message)||"no updatedItems in response";throw h("[SIndex] chunked page fetch failed; aborting full build rather than committing a partial index",{pageSize:t.length,reason:n}),new Error(`Chunked full sync page failed: ${n}`)}return s.updatedItems.filter(j._isItemReadable)}async updatePluginsIndex(e=!1,t){const s=await this.getDataIndexId(t),n=await this.getDataIndex(t);try{const i=await It("/user/plugin/list",{userId:t},{forceRefresh:e});h("[SIndex] Fetched enabled plugins",i),await n.pluginsStore.updatePlugins(i),h("[SIndex] Plugins index updated",{idx:s,enabledCount:i.length})}catch(i){h("[SIndex] Plugins index update failed",i)}}async updateContextsIndex(e=!1,t){try{await(await this.getDataIndex(t)).urlContentStore.update([]),h("[SIndex] Context indices updated")}catch(s){h("[SIndex] Context indices update failed",s)}}};k(j,"_staticInstance",null),k(j,"SYNC_FETCH_CONCURRENCY",4),k(j,"FULL_SYNC_RESUME_MAX_AGE_MS",24*60*60*1e3);let ce=j;const dn=Object.freeze(Object.defineProperty({__proto__:null,IndexService:ce},Symbol.toStringTag,{value:"Module"})),ke=class ke{constructor(){k(this,"connService",V.instance);k(this,"indexService",ce.instance)}static get instance(){return this._staticInstance||(this._staticInstance=new ke),this._staticInstance}async getCurrentUserId(){var e;return(e=await V.instance.getCurrentUser())==null?void 0:e._id}async saveItemLocal(e,t){const n=!(e!=null&&e.itemId)?this.generateTempId():e.itemId;return await this.saveItemLocalWithId(e,n,t)}async saveItemLocalWithId(e,t,s){const n=s||await this.getCurrentUserId(),i=this.buildLocalItem(e,t,n);await this.saveToIndex(i,n);const a=e.collectionIds;return a&&a.length>0&&await this.updateItemRelations(t,a,n),{itemId:t,feedback:i.feedback}}async updateItemFeedbackLocal(e,t){const s=t||await this.getCurrentUserId(),i=(await this.indexService.getDataIndex(s)).itemDataStore,a=await i.getManyByIds([e.itemId]);if(a.length===0)throw new Error(`Item ${e.itemId} not found in local index`);const r=a[0],c=at(e.attr,e.value),o=this.sanitizeForIDB(c);r.feedback={...r.feedback,...o},await i.update([r])}async updateItemLocal(e,t,s){const n=s||await this.getCurrentUserId(),i=await this.indexService.getDataIndex(n),a=await i.itemDataStore.getById(e);if(!a)throw new Error(`Item ${e} not found`);const r={...a.details,...t,updatedAt:new Date},c={...a,details:r};await i.itemDataStore.update([c]);try{await i.urlDetailsStore.update([c])}catch(o){console.error("Failed to update the local URL index after an item update",e,o)}}async storeItems(e,t){if(!e||e.length===0)return;const s=t||await this.getCurrentUserId();await(await this.indexService.getDataIndex(s)).itemDataStore.update(e)}async getItemParents(e,t){const s=t||await this.getCurrentUserId(),n=await this.indexService.getDataIndex(s),a=(await n.itemRelationStore.getRelationsForItem(e)).map(c=>c.collectionId);return a.length===0?[]:await n.itemDataStore.getManyByIds(a)}async getItemsChildren(e,t){const s=t||await this.getCurrentUserId(),n=await this.indexService.getDataIndex(s),a=(await n.itemRelationStore.getRelationsForCollection(e)).map(c=>c.itemId);return a.length===0?[]:await n.itemDataStore.getManyByIds(a)}async deleteItemLocal(e){const t=await this.indexService.getDataIndex(),s=await t.itemRelationStore.getRelationsForItem(e.itemId);if(e.deleteChildren){let n=[];for(const i of s)i.collectionId===e.itemId&&n.push(i.itemId);await t.itemDataStore.deleteIds(n)}
2for(const n of s)await t.itemRelationStore.removeRelation(n.collectionId,n.itemId);await t.itemDataStore.deleteIds([e.itemId])}generateTempId(){return`item_${Date.now()}_${Pt(9)}`}buildLocalItem(e,t,s){var r;const n=new Date().toISOString(),i=this.sanitizeForIDB(e),a=e.feedbackUpdate?this.sanitizeForIDB(at(e.feedbackUpdate.attr,e.feedbackUpdate.value)):void 0;return{itemId:t,details:{_id:t,...i.details,userId:s,createdAt:((r=i.details)==null?void 0:r.createdAt)||n,updatedAt:n},collectionIds:i.collectionIds||[],feedback:a}}sanitizeForIDB(e){if(e==null||typeof e!="object")return e;if(e instanceof Date)return e.toISOString();if(Array.isArray(e))return e.map(s=>this.sanitizeForIDB(s));const t={};for(const s in e)if(e.hasOwnProperty(s)){const n=e[s];if(typeof n=="function"||typeof n=="symbol")continue;t[s]=this.sanitizeForIDB(n)}return t}async saveToIndex(e,t){const s=await this.indexService.getDataIndex(t);await s.itemDataStore.update([e]);try{await s.urlDetailsStore.update([e])}catch(n){console.error("Failed to add saved item to the local URL index",e.itemId,n)}}async getItemById(e,t){const s=t||await this.getCurrentUserId();return await(await this.indexService.getDataIndex(s)).itemDataStore.getById(e)}async getItemsByIds(e,t){if(!e||e.length===0)return[];const s=t||await this.getCurrentUserId();return await(await this.indexService.getDataIndex(s)).itemDataStore.getManyByIds(e)}async createCollection(e){var r;const t=await this.getCurrentUserId(),s=this.generateTempId(),n=new Date().toISOString();let i=((r=e.options)==null?void 0:r.collectionIds)||[];const a={itemId:s,details:{type:rt.collection,name:e.details.name,visibility:e.details.visibility||"private",userId:t,createdAt:n,updatedAt:n},collectionIds:i};return await this.saveToIndex(a,t),i&&i.length>0&&await this.updateItemRelations(s,i,t),s}async updateItemRelations(e,t,s){const i=(await this.indexService.getDataIndex(s)).itemRelationStore,a=await i.getRelationsForItem(e);for(const r of a)await i.removeRelation(r.collectionId,r.itemId);for(let r=0;r<t.length;r++)await i.addRelation({collectionId:t[r],itemId:e,order:r,userId:s})}async addItemToCollection(e,t,s){const n=s||await this.getCurrentUserId(),a=(await this.indexService.getDataIndex(n)).itemRelationStore,c=(await a.getCollectionIdsForItems([e])).get(e)||[];if(!c.includes(t)){const o=c.length;await a.addRelation({collectionId:t,itemId:e,order:o,userId:n})}}async removeItemFromCollection(e,t,s){const n=s||await this.getCurrentUserId();await(await this.indexService.getDataIndex(n)).itemRelationStore.removeRelation(t,e)}async getCollectionIdsForItem(e,t){const s=t||await this.getCurrentUserId();return(await(await this.indexService.getDataIndex(s)).itemRelationStore.getCollectionIdsForItems([e])).get(e)||[]}async listCollections(e){const t=e||await this.getCurrentUserId();return await(await this.indexService.getDataIndex(t)).itemDataStore.listWhere(i=>{var a;return((a=i==null?void 0:i.details)==null?void 0:a.type)===rt.collection})}};k(ke,"_staticInstance");let le=ke;const ut="local_admin",vs="local_restricted",ue=class ue{constructor(e,t,s){this.remoteRequester=e,this.userService=t,this.itemRepo=s}static get instance(){return ue._staticInstance||(ue._staticInstance=new ue(G.instance,ye.instance,le.instance)),ue._staticInstance}getReqErrorStatus(e){const t=(e==null?void 0:e.status)??(e==null?void 0:e.statusCode);return typeof t=="number"?t:void 0}isExpectedFederatedNoAccount(e,t){var s;return[we.google,we.apple].includes(e)?((s=t==null?void 0:t.message)==null?void 0:s.trim())==="User not found"&&this.getReqErrorStatus(t)===409:!1}announceAuthInfo(e){Ee.emit("auth-info-updated",{success:(e==null?void 0:e.success)===!0,authInfo:e})}async _noteFreshSignIn(e){await Xt(e)}async _updateAuth(e){var t,s;if(h("update Auth Info:",e),e==null||e.success,(t=e==null?void 0:e.user)!=null&&t._id,(s=e==null?void 0:e.tokenData)!=null&&s.token,e.success==!0)return await V.instance.updateAuthInfo(e),this.announceAuthInfo(e),gs(e.user).catch(()=>{}),!0;throw this.announceAuthInfo(e),console.error("Error signin failed",e),Error("Login failed")}async signOut(){const e=await this.userService.getCurrentUser().catch(()=>null);await ve.instance.runSignoutCallbacks();const t=await R();try{t||await this.remoteRequester.remoteRequestRaw("/auth/signout")}catch(s){(s==null?void 0:s.status)===401||(s==null?void 0:s.errorType)==="AUTH"?h("Signout skipped: already unauthenticated",s):console.error("Error signing out",s)}finally{await st.instance.clearUserKeyManager(e==null?void 0:e._id),st.instance.clearAllKeyManagers(),await V.instance.reset()}}async exportHandoffMaterial(){var i;if(await R())return null;const e=await V.instance.getAuthInfo(),t=(i=e==null?void 0:e.tokenData)==null?void 0:i.token,s=e==null?void 0:e.user;if(!t||!(s!=null&&s._id))return null;const n=await J.getEncPassword(s._id);return{token:t,encPassword:n||null,userId:s._id,userSnapshot:s}}async importHandoffMaterial(e){if(!(e!=null&&e.token)||!(e!=null&&e.userId)||!(e!=null&&e.userSnapshot))throw new O("Handoff material incomplete",400);const t=await V.instance.getCurrentAuthToken();if(t&&t===e.token)return h("[handoff] session already seeded with this token"),e.encPassword&&(await J.setEncPassword(e.userId,e.encPassword),await N.instance.encStatus(new nt(e.userSnapshot),!0)),{success:!0};await this.signOut();const s={success:!0,user:e.userSnapshot,tokenData:{token:e.token,expAtSec:null}};await this._updateAuth(s),e.encPassword&&await J.setEncPassword(e.userId,e.encPassword);const n=await N.instance.encStatus(new nt(e.userSnapshot),!0);return h("[handoff] enc status after import",n),lt(e.userSnapshot,"login"),{success:!0}}async switchUser(e,t){const s=await R()?await this._switchUserLocal(e,t):await this._switchUserRemote(e,t);return Ee.emit("active-user-changed",{userId:e||null}),s}async _switchUserLocal(e,t){const s=await this.userService.getUserById(e);if(!s)throw new O("User not found",404);const n=await M.hashPassword(t,D.passwordSalt),i=await V.instance.getCurrentUser();
2if(s.type===ge.admin&&i._id!==s._id)throw new O("Cannot switch to an admin account",403);if(i.type!==ge.admin&&s.pin!==n)throw new O("Invalid PIN",401);return await V.instance.updateUserObj(s),{user:s,tokenData:null,lastUpdated:new Date,success:!0}}async _switchUserRemote(e,t){const s=await this.userService.getCurrentUser(),n=await this.userService.getUserById(e,!0);if(h("[ENC:SWITCH_USER] Starting user switch",{fromUserId:s==null?void 0:s._id,fromUserType:s.type,toUserId:e,toUserType:n.type}),s.type=="admin"&&n.type=="restricted"){h("[ENC:SWITCH_USER] AdminâRestricted: Pre-caching target user secret key");try{const d=await N.instance.getKeyManager(await this.userService.getUserRequestContext(s==null?void 0:s._id),!0),u=M.getUserSecretKeyId(e),f=await d.getSecretKeyById(u);f!=null&&f.keyString?(await J.setEncSecretyKey(e,f.keyString),h("[ENC:SWITCH_USER] Pre-cached secret key for restricted user",{userId:e})):h("[ENC:SWITCH_USER] Admin KeyManager missing restricted user secret key",{userId:e,userSecretKeyId:u,adminHasKey:!1})}catch(d){h("[ENC:SWITCH_USER] Error pre-caching restricted user secret key",d)}}await ve.instance.runSignoutCallbacks();const i=await xe(),a=await S("/auth/switchUser",{userId:e,pinpass:t?await M.hashPassword(t,D.passwordSalt):null,clientInfo:i});if(!a.success)throw new O("Switch user failed",400);const r=a.passwordForClient;if(h("[ENC:SWITCH_USER] Processing credentials from server",{userId:e,hasPassword:!!r,hasRecoveryKey:!!a.recoveryKeyForClient}),r){const d=await M.hashPassword(r,D.passwordEncSalt);await J.setEncPassword(e,d),h("[ENC:SWITCH_USER] Stored enc password for user",{userId:e})}const c=a.recoveryKeyForClient;c&&(await J.setEncRecoveryKey(e,c),h("[ENC:SWITCH_USER] Stored recovery key for user",{userId:e})),h("[ENC:SWITCH_USER] Updating auth info");const o=await this._updateAuth(a),l=await oe(Ft.deviceRegistrationToken);return Ee.emit("auth-session-rebound",{deviceRegistrationToken:l||void 0,reconnectSse:!D.isMobileApp&&!D.browser_mode}),o}async updatePIN(e,t){const s=await M.hashPassword(t,D.passwordSalt);return await R()?(e=e||await this.userService.getCurrentUserId(),await ee.instance.updateUserPINLocal(e,s)):await S("/auth/updatePIN",{userId:e,pin:s})}async register(e,t,s=!1){try{const{password:n,loginType:i,refData:a}=e,r=n?await M.hashPassword(n,D.passwordSalt):null;let c={...e,password:r};i!="internal"&&t&&n&&(c.serverCopyOfPassword=n);const o=await this.remoteRequester.remoteRequestRaw("/auth/register",c),l=await Ie(o,"/auth/register");await this.updateAuthInfoOnClient(l,i,n);try{const u=await this.userService.getUserRequestContext(),f=await N.instance.generateKeys(u);u.isCurrentUser&&(f!=null&&f.cachedUserSecretKeyString)&&await J.setEncSecretyKey(u.userId,f.cachedUserSecretKeyString),!s&&t&&await N.instance.saveRecoveryKeyOnServer(u)}catch(u){throw console.error("Error setting up encryption for user",u),new O("Error setting up encryption",500,u)}const d=a==null?void 0:a.sessionToken;return d&&await S("/auth/providerLogin/confirmSession",{sessionToken:d}),l.user}catch(n){throw console.error("Register Error:",n),new O(n.message,500,n)}}async completeEncryptionSetup(e){const t=await this.userService.getUserRequestContext();e==="server"&&await N.instance.saveRecoveryKeyOnServer(t);const s=await N.instance.encStatus(await this.userService.getUserRequestContext(),!0);return h("Enc Status:",s),{success:!0}}async permissionOverride(e){if(await R()){const s=await this.userService.getUserById(e.overrideUserId);if(!s)throw new O("User not found",404);const n=await M.hashPassword(e.pinpass,D.passwordSalt);if(s.pin!==n)throw new O("Invalid PIN",401);return{success:!0,overrideUserId:s._id,tokenData:{token:`LOCAL_OVERRIDE:${s._id}:${Date.now()}`,expAtSec:Math.floor(Date.now()/1e3)+60*5}}}return await S("/auth/permissionOverride",{overrideUserId:e.overrideUserId,pinpass:await M.hashPassword(e.pinpass,D.passwordSalt)},{disablePermissionOverrideToken:!0})}async tokenSignIn(e,t={}){var l,d,u,f;if(await V.instance.getCurrentAuthToken()==e)return h("Already logged in with this token"),!0;await this.signOut();const n=await xe(),i=await this.remoteRequester.remoteRequestRaw("/auth/tokenLogin",{token:e,clientInfoData:n},{serverBaseURLOverride:t.serverBaseURLOverride}),a=await Ie(i,"/auth/tokenLogin"),r=a&&typeof a=="object"&&a.results&&typeof a.results=="object"?a.results:a;if((a==null?void 0:a.success)===!0&&r&&r.success==null&&(r.success=!0),!(r!=null&&r.success)||!(r!=null&&r.user)||!((l=r==null?void 0:r.tokenData)!=null&&l.token))throw console.error("[tokenSignIn] tokenLogin response missing expected fields",{hasSuccess:!!(r!=null&&r.success),hasUser:!!(r!=null&&r.user),hasToken:!!((d=r==null?void 0:r.tokenData)!=null&&d.token)}),new Error("Login failed");const c=await this._updateAuth(r);await this._noteFreshSignIn((u=r==null?void 0:r.user)==null?void 0:u._id);try{const y=(f=r==null?void 0:r.user)==null?void 0:f._id;if(y){const m=r.passwordForClient;if(m){const I=await M.hashPassword(m,D.passwordEncSalt);await J.setEncPassword(y,I),h("[tokenSignIn] Stored enc password from tokenLogin",{userId:y})}const w=r.recoveryKeyForClient;w&&(await J.setEncRecoveryKey(y,w),h("[tokenSignIn] Stored recovery key from tokenLogin",{userId:y}))}else h("[tokenSignIn] tokenLogin response missing userId; cannot persist credentials")}catch(y){console.error("[tokenSignIn] Failed to persist tokenLogin credentials",y)}const o=await N.instance.encStatus(await this.userService.getUserRequestContext(),!0);return h("Enc Status:",o),c}async signinlocal(){try{const e=await ee.instance.listAccountUsersLocalOnly();if(e&&e.length>0){e.length;const t=await ee.instance.getUserByIdLocalOnly(ut);if(t){await V.instance.updateUserObj(t);const s={success:!0,tokenData:{token:null,expAtSec:null},user:t},n=await this._updateAuth(s);return await this._noteFreshSignIn(t._id),n}}}catch{}try{const e=await ee.instance.createLocalUser({_id:"local_admin",username:"local_admin",localUser:!0,displayedName:"Local User",type:ge.admin});let t={success:!0,tokenData:{token:null,expAtSec:0}
2,user:e};await this._updateAuth(t),await this._noteFreshSignIn(e._id);let s=await this.itemRepo.createCollection({details:{name:"QuickBar",visibility:"shared",userId:e._id}});return await ee.instance.updateUser(e._id,{quickBarCollectionId:s}),t}catch(e){throw console.error("Error during local account setup:",e),new O("Failed to create local account",500,e)}}async createRestrictedLocal(){const e=await ee.instance.getUserByIdLocalOnly(vs),t=await ee.instance.getUserByIdLocalOnly(ut);if(await ee.instance.updateUser(t._id,{displayedName:"Parent",profileImage:{data:"/profile_images/person-gear.svg",type:"path"}}),e)return e;try{const s=await ee.instance.createLocalUser({_id:"local_restricted",localUser:!0,username:"local_restricted",displayedName:"Kiddo",type:ge.restricted,profileImage:{data:"/profile_images/ladybug-svgrepo-com.svg",type:"path"},options:{whitelistingEnabled:!0,codeInjectionEnabled:!0,contentFilteringEnabled:!0,logActivity:!0}});return await ee.instance.updateUser(s._id,{quickBarCollectionId:t.quickBarCollectionId}),s}catch(s){throw console.error("Error during local account setup:",s),new O("Failed to create local account",500,s)}}async signIn(e){var c;const{username:t,password:s,loginType:n,loginPayload:i={},recaptchaToken:a}=e,r=n===we.apple||n===we.google;if(!r&&s.length<8&&D.nodeEnv!="development")throw new O("Password must be at least 8 characters",400);try{const o=await xe(),l=await this.remoteRequester.remoteRequestRaw("/auth/signin",{username:t,password:s?await M.hashPassword(s,D.passwordSalt):null,loginType:n,loginPayload:i,recaptchaToken:a,clientInfoData:o});h("signin Response",l);const d=await Ie(l,"/auth/signin");return r&&(d!=null&&d.success)&&((c=d==null?void 0:d.tokenData)!=null&&c.token)?await this.tokenSignIn(d.tokenData.token):await this.updateAuthInfoOnClient(d,n,s)}
2catch(o){throw o instanceof O?(this.isExpectedFederatedNoAccount(n,o)?h("Signin expected auth miss",{loginType:n,message:o.message,status:this.getReqErrorStatus(o)}):console.error("Signin Error:",o),o):(console.error("Signin Error:",o),new O((o==null?void 0:o.message)||"Sign in failed",500,o))}}async recoverAccountAccess(e){try{const t=await xe(),s=await this.remoteRequester.remoteRequestRaw("/auth/recoverAccountAccess",{verificationCode:e,clientInfoData:t}),n=await Ie(s,"/auth/recoverAccountAccess");return await this.updateAuthInfoOnClient(n,"recovery",null)}catch(t){throw console.error("Recover account access error:",t),new O(t.message,500,t)}}async signInWithPasskey(e){try{const t=await this.remoteRequester.remoteRequestRaw("/auth/passkey/login",{credentialId:e.credentialId,signature:e.signature,authenticatorData:e.authenticatorData,clientDataJSON:e.clientDataJSON});h("Passkey signin Response",t);const s=await Ie(t,"/auth/passkey/login");return await this.updateAuthInfoOnClient(s,"passkey",null)}catch(t){throw console.error("Passkey Signin Error:",t),new O(t.message,500,t)}}async updateAuthInfoOnClient(e,t,s=null){var c;if(!e.success){const o=this.isExpectedFederatedNoAccount(t,{message:e.message,status:e.statusCode});throw o?h("Signin expected auth miss",{loginType:t,message:e.message,status:e.statusCode}):console.error("Signin unsuccessful:",e.message,e.statusCode),e.statusCode==409?new O(e.message,e.statusCode,{message:e.message},o?"AUTH":void 0):new O("Login failed:"+e.message,e.statusCode,{message:e.message})}let n=s;if((t===we.apple||t===we.google||t==="passkey")&&n==null&&(n=e.passwordForClient),!await this._updateAuth(e))throw new O("Error updating auth",500);const a=((c=e==null?void 0:e.user)==null?void 0:c._id)||await this.userService.getCurrentUserId();if(!a)throw new O("Authenticated user id missing after signin",500);if(await this._noteFreshSignIn(a),h("[ENC:AUTH_UPDATE] Setting encryption credentials",{userId:a,hasPassword:!!n,hasRecoveryKey:!!e.recoveryKeyForClient,loginType:t}),n!=null){const o=await M.hashPassword(n,D.passwordEncSalt);await J.setEncPassword(a,o)}e.recoveryKeyForClient!=null&&await J.setEncRecoveryKey(a,e.recoveryKeyForClient);const r=await N.instance.encStatus(await this.userService.getUserRequestContext(),!0);return h("Enc Status:",r),h("[ENC:AUTH_UPDATE] Enc status after auth update",{userId:a,userEncSetup:r.userEncSetup,userEncEnabled:r.userEncEnabled,acntEncSetup:r.acntEncSetup,acntEncEnabled:r.acntEncEnabled}),lt(e.user,"login"),e.user}async updatePassword(e){if(await R())throw new O("Not available in local only mode",400);const{userId:t,password:s,currentPassword:n,forceSkipCheck:i}=e,a=await this.userService.getCurrentUser();let c=!t||t==(a==null?void 0:a._id)?a:await this.userService.getUserById(t);const o=await this.userService.getUserRequestContext(c._id),l=await N.instance.encStatus(o,!0);if(l.userEncSetup){if(!i&&c.hasPassword&&!await this.checkPassword(n,c._id))throw new O("Incorrect current password",400);if(l.userEncSetup==!0&&l.userEncEnabled){const y=await M.hashPassword(s,D.passwordEncSalt);await N.instance.setEncPassword(o,y)}}let d=null;c.hasPasswordCopy&&(d=s);const u=await this.remoteRequester.remoteRequestRaw("/auth/updatePassword",{userId:t,password:await M.hashPassword(s,D.passwordSalt),passwordCopy:d});if(!await this.checkPassword(s,c._id))throw new O("Error testing password",400);return u}async resetPassword(e){const{verificationCode:t,password:s}=e,n=await M.hashPassword(s,D.passwordSalt);return await this.remoteRequester.remoteRequestRaw("/auth/resetPassword",{password:n,verificationCode:t})}async checkPassword(e,t=null){const s=await M.hashPassword(e,D.passwordSalt),n=await S("/auth/checkPassword",{password:s,userId:t??void 0});if(n.valid){const i=t||await this.userService.getCurrentUserId(),a=await M.hashPassword(e,D.passwordEncSalt);await J.setEncPassword(i,a)}return n.valid}async checkTempDisableBlocking(){var n;let e=await this.userService.getCurrentUser();if(!e)return!1;let t=(n=e==null?void 0:e.options)==null?void 0:n.accessControlSettings,s=!1;return t!=null&&t.disableRestrictions&&(t==null?void 0:t.disableRestrictionsExpires)>new Date().getTime()&&(s=!0),s}};k(ue,"_staticInstance",null);let Ge=ue;const Rs="knd:in-page-lazy-seam";let be=null;function Cs(){return be||(h("[fetchmeta] loading the metadata parser",Rs),be=Ve(()=>import("./fetchmetak7U1zgO7.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])).catch(p=>{throw be=null,p})),be}async function Us(p,e={}){return(await Cs()).fetchRawMetaBrowser(p,e)}function ze(p,e){return p!==void 0?p:e}function W(){return typeof performance<"u"?performance.now():Date.now()}function Z(p){return Math.round(Math.max(0,p)*10)/10}const B=class B{constructor(e){k(this,"pieceUploads",new Map);k(this,"pieceReads",new Map);this.userService=e}static get instance(){return B._staticInstance||(B._staticInstance=new B(ye.instance)),B._staticInstance}
2async uploadUserFile(e,t=!1){if(await R())return await this.uploadUserFileLocal(e);const{encInfo:s}=e,n=this._dataUrlOrBase64ToBytes(e.fileData),a=(!!s||t)&&n.length>=B.CHUNK_THRESHOLD_BYTES,r=(e.previews||[]).filter(d=>!!(d!=null&&d.data)),c={...e,previews:void 0};if(a){const d=await this.uploadUserFileChunked(c,n,t);return await this._uploadPreviews(d==null?void 0:d._id,r,(d==null?void 0:d.encInfo)??null),d}let o=c;if(s!=null){const d=await this.userService.getUserRequestContext(),u=await N.instance.getKeyManager(d),f={...s,v:1,iv:M.ab2str(crypto.getRandomValues(new Uint8Array(12)))};o=(await u.encryptObjectUsingEncInfo(f,c,{fileData:{encrypted:!0,type:"string"}})).obj,o.encInfo=f}else if(t&&!s){const d=await this.userService.getUserRequestContext(),u=await N.instance.getKeyManager(d),f=await u.encryptObjectWithKeyIds([u.getAcntSecretKeyId()],c,{fileData:{encrypted:!0,type:"string"}},!1,1);o=f.obj,o.encInfo=f.encInfo}let l;try{l=await this.uploadUserFileBinary(o)}catch(d){h("Binary userfile upload failed; falling back to legacy /userfile/upload",d),l=await S("/userfile/upload",o)}return await this._uploadPreviews(l==null?void 0:l._id,r,o.encInfo??null),l}async _uploadPreviews(e,t,s){if(!e||!t||t.length===0)return;const n=s?await N.instance.getKeyManager(await this.userService.getUserRequestContext()):null;for(const i of t){const a=String(i.id??"0");let r=i.data,c;n&&s&&(c=M.ab2str(crypto.getRandomValues(new Uint8Array(12))),r=(await n.encryptObjectUsingEncInfo({...s,v:1,iv:c},{data:r},{data:{encrypted:!0,type:"string"}})).obj.data);try{await S("/userfile/uploadPreview",{fileId:e,previewId:a,data:r,iv:c})}catch(o){h("Preview upload failed; continuing without a thumbnail",o)}}}_fileDataToBase64(e){let t=e??"";if(t.length>1&&t.startsWith('"')&&t.endsWith('"'))try{t=JSON.parse(t)}catch{t=t.slice(1,-1)}return t.startsWith("data:")?t.split(",")[1]:t}_dataUrlOrBase64ToBytes(e){return new Uint8Array(M.str2ab(this._fileDataToBase64(e)))}_u8ToArrayBuffer(e){return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}_parseMultipartBoundary(e){if(!e)return null;const s=e.split(";").map(i=>i.trim()).find(i=>i.toLowerCase().startsWith("boundary="));if(!s)return null;let n=s.substring(9);return n=n.trim(),n.startsWith('"')&&n.endsWith('"')&&(n=n.slice(1,-1)),n||null}_findAllOccurrences(e,t){const s=[];if(t.length===0||e.length<t.length)return s;e:for(let n=0;n<=e.length-t.length;n++){for(let i=0;i<t.length;i++)if(e[n+i]!==t[i])continue e;s.push(n),n+=t.length-1}return s}_indexOfBytes(e,t,s=0){if(t.length===0)return s;e:for(let n=s;n<=e.length-t.length;n++){for(let i=0;i<t.length;i++)if(e[n+i]!==t[i])continue e;return n}return-1}_parseMultipartMixed(e,t){const s=new TextEncoder,n=new TextDecoder,i=s.encode(`--${t}`),a=s.encode(`\r 3\r 4`),r=this._findAllOccurrences(e,i);if(r.length<2)throw new Error("Invalid multipart: boundary not found");const c=[];for(let o=0;o<r.length-1;o++){const l=r[o],d=r[o+1];let u=l+i.length;if(e[u]===45&&e[u+1]===45)break;e[u]===13&&e[u+1]===10&&(u+=2);let f=d;f>=2&&e[f-2]===13&&e[f-1]===10&&(f-=2);const y=e.slice(u,f);if(y.length===0)continue;const m=this._indexOfBytes(y,a,0);if(m<0)throw new Error("Invalid multipart: missing header separator");const w=y.slice(0,m),I=y.slice(m+a.length),U=n.decode(w),F={};for(const _ of U.split(`\r 5`)){const C=_.indexOf(":");if(C<=0)continue;const A=_.slice(0,C).trim().toLowerCase(),v=_.slice(C+1).trim();F[A]=v}c.push({headers:F,body:I})}return c}_deriveChunkIv(e,t){if(e.length!==8)throw new Error("Invalid chunk salt length");const s=new Uint8Array(12);return s.set(e,0),new DataView(s.buffer).setUint32(8,t>>>0,!1),s}_chunkAad(e,t,s,n){const i=JSON.stringify({v:n,fileId:e,chunkIndex:t,chunkSize:s});return new TextEncoder().encode(i)}async _getCryptoKeyForEncInfo(e,t){if(!t||typeof t!="object"||!Array.isArray(t.keys))throw new Error("Invalid encInfo");for(const s of t.keys)try{const n=s==null?void 0:s.unwrappingKeyId;if(!n)continue;const i=await e.getKey(n);if(!i)continue;return s!=null&&s.wrappedEncKey?(await e.wrappedKeyToKeyInstance(i,s.wrappedEncKey)).key:i.key}catch{continue}throw new Error("Failed to unwrap file encryption key")}async uploadUserFileChunked(e,t,s){const n=await this.userService.getUserRequestContext(),i=await N.instance.getKeyManager(n),a=B.DEFAULT_CHUNK_SIZE_BYTES,r=Math.ceil(t.length/a);let c=e.encInfo??null;if(!c&&!s)throw new Error("Chunked upload requires encInfo or forceEncrypt");
5if(!c){const I=i.getAcntSecretKeyId(),U=await i.getKey(I);if(!U)throw new Error("Wrapping key not available");const F=await M.createSecretKey("onetime","onetime","onetime",["encrypt","decrypt"]),_=await i.wrap(F,U);c={keys:[{wrappedEncKey:{iv:M.ab2str(_.iv),wrappedData:M.ab2str(_.wrappedData),keyAlgo:M.serializeAlgo(_.keyAlgo)},wrappingKeyId:I,unwrappingKeyId:I}],v:1,iv:M.ab2str(crypto.getRandomValues(new Uint8Array(12)))}}const o=crypto.getRandomValues(new Uint8Array(8)),l=1;c.chunked={v:l,chunkSize:a,chunkCount:r,salt:M.ab2str(o)};const d={ufId:e.ufId,refId:e.refId,refType:e.refType,fileType:e.fileType,filename:e.filename,encInfo:c,fileSize:t.length,chunkSize:a,chunkCount:r},f=await(await G.instance.remoteRequestRaw("/userfile/uploadChunkedInit",d,{method:"POST"})).json();if(!(f!=null&&f.success))throw new Error((f==null?void 0:f.message)||"Chunked init failed");const y=f.results,m=y==null?void 0:y._id;if(!m)throw new Error("Chunked init did not return file id");const w=await this._getCryptoKeyForEncInfo(i,c);for(let I=0;I<r;I++){const U=I*a,F=Math.min(t.length,U+a);await this._encryptAndUploadChunk({fileId:String(m),cryptoKey:w,chunkSalt8:o,chunkSize:a,chunkingVersion:l},I,t.slice(U,F))}return{...y,encInfo:c}}async _encryptAndUploadChunk(e,t,s){const n=this._deriveChunkIv(e.chunkSalt8,t),i=this._chunkAad(e.fileId,t,e.chunkSize,e.chunkingVersion),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:this._u8ToArrayBuffer(n),additionalData:this._u8ToArrayBuffer(i),tagLength:128},e.cryptoKey,this._u8ToArrayBuffer(s)),c=await(await G.instance.remoteRequestRaw("/userfile/uploadChunk",{},{method:"POST"},{headers:{"Content-Type":"application/octet-stream","x-userfile-id":e.fileId,"x-chunk-index":String(t)},body:new Uint8Array(a)})).json();if(!(c!=null&&c.success))throw new Error((c==null?void 0:c.message)||`Chunk upload failed at index ${t}`)}_dropIdlePieceSessions(){const e=Date.now()-B.PIECE_SESSION_IDLE_MS;for(const[t,s]of this.pieceUploads)s.touchedAt<e&&this.pieceUploads.delete(t);for(const[t,s]of this.pieceReads)s.touchedAt<e&&this.pieceReads.delete(t)}async _withRetry(e,t=3){let s;for(let n=0;n<t;n++)try{return await e()}catch(i){s=i,n<t-1&&await new Promise(a=>setTimeout(a,500*3**n))}throw s}async startFilePieces(e){var o;this._dropIdlePieceSessions();const t=Number(e.fileSize);if(!Number.isFinite(t)||t<=0)throw new Error("A file sent in pieces needs its size");const s=B.DEFAULT_CHUNK_SIZE_BYTES,n=Math.ceil(t/s),{fileSize:i,...a}=e,r={request:a,fileSize:t,chunkSize:s,chunkCount:n,received:0,touchedAt:Date.now()};if(a.encInfo&&!await R()){const l=await this.userService.getUserRequestContext(),d=await N.instance.getKeyManager(l),u=crypto.getRandomValues(new Uint8Array(8)),f=1,y={...a.encInfo,chunked:{v:f,chunkSize:s,chunkCount:n,salt:M.ab2str(u)}},w=await(await G.instance.remoteRequestRaw("/userfile/uploadChunkedInit",{ufId:a.ufId,refId:a.refId,refType:a.refType,fileType:a.fileType,filename:a.filename,encInfo:y,fileSize:t,chunkSize:s,chunkCount:n},{method:"POST"})).json();if(!(w!=null&&w.success))throw new Error((w==null?void 0:w.message)||"Chunked init failed");const I=(o=w.results)==null?void 0:o._id;if(!I)throw new Error("Chunked init did not return file id");r.fileRef=w.results,r.encInfo=y,r.target={fileId:String(I),cryptoKey:await this._getCryptoKeyForEncInfo(d,y),chunkSalt8:u,chunkSize:s,chunkingVersion:f}}else r.gathered=[];const c=crypto.randomUUID();return this.pieceUploads.set(c,r),{uploadId:c,pieceSize:s}}async putFilePieces(e){const t=this.pieceUploads.get(e.uploadId);if(!t)throw new Error(Ae);t.touchedAt=Date.now();const s=Number(e.index);if(!Number.isInteger(s)||s<0||s>t.received)throw new Error("File pieces must arrive in order");const n=this._dataUrlOrBase64ToBytes(e.data);if(n.length>B.MAX_PIECE_REQUEST_BYTES)throw new Error("Too many file pieces in one request");const i=Math.ceil(n.length/t.chunkSize);if(i===0||s+i>t.chunkCount)throw new Error("More file pieces than the file has");for(let a=0;a<i;a++){const r=s+a,c=n.subarray(a*t.chunkSize,Math.min(n.length,(a+1)*t.chunkSize)),o=r===t.chunkCount-1?t.fileSize-(t.chunkCount-1)*t.chunkSize:t.chunkSize;if(c.length!==o)throw new Error("A file piece is the wrong size");if(t.target){const l=t.target;await this._withRetry(()=>this._encryptAndUploadChunk(l,r,c))}else t.gathered[r]=c.slice()}return t.received=Math.max(t.received,s+i),{next:t.received}}async finishFilePieces(e){const t=this.pieceUploads.get(e.uploadId);if(!t)throw new Error(Ae);if(t.received!==t.chunkCount)throw new Error("The upload is missing file pieces");this.pieceUploads.delete(e.uploadId);const s=(e.previews||[]).filter(a=>!!(a!=null&&a.data));if(t.target)return await this._uploadPreviews(t.target.fileId,s,t.encInfo),{...t.fileRef,encInfo:t.encInfo};const n=new Uint8Array(t.fileSize);let i=0;for(const a of t.gathered)n.set(a,i),i+=a.length;return await this.uploadUserFile({...t.request,fileData:M.ab2str(n),previews:s})}async openFilePieces(e){var i,a,r;this._dropIdlePieceSessions();const t=String((e==null?void 0:e.fileId)||"").replace(/^uf_/,"");if(!t)throw new Error("A file id is needed");let s=null;if(!await R()){const c=await S("/userfile/getMetaById",{fileId:t}),o=c==null?void 0:c.userFile;if(o!=null&&o._id&&((i=o.encInfo)!=null&&i.chunked)){const l=await this.createChunkedUserFileRangeReader(o);s={size:Number(l.fileSize??o.fileSize??0),fileType:o.fileType??null,filename:o.filename??null,touchedAt:Date.now(),readRange:l.readRange}}}if(!s){const c=await this.getUserFileById({fileId:t},!0,!1),o=this._dataUrlOrBase64ToBytes(String((c==null?void 0:c.data)??""));s={size:o.length,fileType:((a=c==null?void 0:c.userFile)==null?void 0:a.fileType)??null,filename:((r=c==null?void 0:c.userFile)==null?void 0:r.filename)??null,touchedAt:Date.now(),readRange:async(l,d)=>o.slice(l,l+d)}}const n=crypto.randomUUID();return this.pieceReads.set(n,s),{readId:n,size:s.size,fileType:s.fileType,filename:s.filename}}async readFilePieces(e){const t=this.pieceReads.get(e.readId);if(!t)throw new Error(Ae);t.touchedAt=Date.now();const s=Number(e.offset),n=Number(e.length);if(!Number.isInteger(s)||!Number.isInteger(n)||s<0||n<0)throw new Error("Invalid range");if(n>B.MAX_PIECE_REQUEST_BYTES)throw new Error("Too many file pieces in one request");const i=Math.min(t.size,s+n),a=i>s?await this._withRetry(()=>t.readRange(s,i-s)):new Uint8Array(0);return{data:M.ab2str(a)}}closeFilePieces(e){return e!=null&&e.readId&&this.pieceReads.delete(e.readId),e!=null&&e.uploadId&&this.pieceUploads.delete(e.uploadId),{}}
5async _fetchCiphertextChunkRange(e,t,s){const n=await G.instance.remoteRequestRaw("/userfile/getCiphertextChunkRange",{fileId:e,startChunk:t,chunkCount:s},{method:"POST"},{headers:{Accept:"application/octet-stream"}});if(!n.ok)throw new Error(`Chunk range fetch failed: ${n.status}`);const i=await n.arrayBuffer(),a=new Uint8Array(i),r=[];let c=0;for(;c+4<=a.length;){const l=new DataView(a.buffer,a.byteOffset+c,4).getUint32(0,!1);if(c+=4,c+l>a.length)throw new Error("Invalid chunk framing");r.push(a.slice(c,c+l)),c+=l}return r}async createChunkedUserFileRangeReader(e){const t=e==null?void 0:e.encInfo,s=t==null?void 0:t.chunked;if(!s||typeof s!="object")throw new Error("UserFile is not chunked");const n=Number(s.chunkSize),i=Number(s.chunkCount),a=String(s.salt),r=Number(s.v??1);if(!Number.isFinite(n)||n<=0)throw new Error("Invalid chunkSize");if(!Number.isFinite(i)||i<=0)throw new Error("Invalid chunkCount");const o=new Uint8Array(M.str2ab(a)).slice(0,8);if(o.length!==8)throw new Error("Invalid chunk salt");const l=await this.userService.getUserRequestContext(),d=await N.instance.getKeyManager(l),u=await this._getCryptoKeyForEncInfo(d,t),f=String(e._id),y=Number(e.fileSize??NaN),m=async(w,I)=>{if(w<0||I<0)throw new Error("Invalid range");if(I===0)return new Uint8Array(0);const U=w+I,F=Math.floor(w/n),_=Math.floor((U-1)/n),C=new Uint8Array(I);let A=0;for(let v=F;v<=_;v+=B.DEFAULT_CHUNK_RANGE_BATCH){const T=Math.min(B.DEFAULT_CHUNK_RANGE_BATCH,_-v+1),E=await this._fetchCiphertextChunkRange(f,v,T);for(let x=0;x<E.length;x++){const q=v+x,z=this._deriveChunkIv(o,q),g=this._chunkAad(f,q,n,r),b=await crypto.subtle.decrypt({name:"AES-GCM",iv:this._u8ToArrayBuffer(z),additionalData:this._u8ToArrayBuffer(g),tagLength:128},u,this._u8ToArrayBuffer(E[x])),P=new Uint8Array(b),L=q*n,H=Math.max(0,w-L),K=Math.min(P.length,U-L);if(K<=H)continue;const Y=P.slice(H,K);C.set(Y,A),A+=Y.length}}return C};return{fileId:f,chunkSize:n,chunkCount:i,fileSize:Number.isFinite(y)?y:null,readRange:m}}async _readChunkedUserFileResult(e,t){const s=Number((e==null?void 0:e.fileSize)??NaN);if(!Number.isFinite(s)||s<0)throw new Error("Chunked userfile missing fileSize");if(s>B.MAX_CHUNKED_RECONSTRUCT_BYTES)throw new Error(`Chunked userfile too large for full reconstruction (${Math.round(s/1024/1024)} MiB). Use chunk-range reads instead.`);const i=await(await this.createChunkedUserFileRangeReader(e)).readRange(0,s),a=M.ab2str(this._u8ToArrayBuffer(i));return this.createResultFileObject(a,e,t)}async uploadUserFileBinary(e){const t=this._dataUrlOrBase64ToBytes(e.fileData);await this.userService.getUserRequestContext();const s=JSON.stringify({ufId:e.ufId,refId:e.refId,refType:e.refType,fileType:e.fileType,filename:e.filename,encInfo:e.encInfo??null}),i=await(await G.instance.remoteRequestRaw("/userfile/uploadBinary",{},{method:"POST"},{headers:{"Content-Type":"application/octet-stream","x-userfile-info":s},body:t})).json();if(!(i!=null&&i.success))throw new Error((i==null?void 0:i.message)||"Binary upload failed");return i.results}async uploadUserFileLocal(e){const t=await this.userService.getCurrentUserId(),s=`file_localfile_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,n={_id:s,refId:e.refId,refType:e.refType,filename:e.filename||"file",fileType:e.fileType,fileData:e.fileData,previews:e.previews,encInfo:e.encInfo,secure:e.secure,userId:t,createdAt:new Date().toISOString()};return await(await ae()).userFiles.put(n),h("FileService: Uploaded file locally",s),{_id:s,filename:e.filename||"file",filesize:e.fileData.length,createdAt:new Date().toISOString()}}async listUserFilesByRef(e,t){if(!await R())return S("/userfile/listFilesByRef",{refType:e,refId:t});try{return(await(await ae()).getFilesByRef(e,t)).map(a=>({_id:a._id,filename:a.filename,filesize:a.fileData?a.fileData.length:0,createdAt:a.createdAt||null}))}catch(s){return h("FileService: Error listing files by ref",s),[]}}async decryptUserFileWithId(e){const{data:t,userFile:s}=await this.getUserFileById({fileId:e},!0);if(s!=null&&s.encInfo){let n=s,i={ufId:n._id,fileData:t,refId:n.refId,refType:n.refType,f
5ilename:n.filename,fileType:n.fileType,encInfo:null};await this.uploadUserFile(i)}}async encryptUserFileWithId(e,t=null){const{data:s,userFile:n}=await this.getUserFileById({fileId:e},!0);if(!n.encInfo){let i=n,a={ufId:i._id,fileData:s,refId:i.refId,refType:i.refType,filename:i.filename,fileType:i.fileType,encInfo:t};await this.uploadUserFile(a,!0)}}async getUserFileByIdStream(e,t=!1){const s=await G.instance.remoteRequestRaw("/userfile/getById",e);h("getUserFileById",e,s);const i=(await s.text()).split($t),a=i[0],r=i[1],c=a,o=JSON.parse(r),l=await this.userService.getUserRequestContext(),d=await N.instance.getKeyManager(l);if(h("getUserFileById jsonObject",o,c),!o.encInfo)return t==!0?{data:c,userFile:o}:c;const u=await d.decryptObject({data:JSON.stringify(c)},{data:{encrypted:!0,type:"string"}},this._encInfoForRead(o.encInfo,e==null?void 0:e.previewId));return t==!0?{data:u==null?void 0:u.data,userFile:o}:{data:u==null?void 0:u.data}}_encInfoForRead(e,t){var n,i;if(t==null||t==="undefined")return e;const s=(i=(n=e==null?void 0:e.previewMeta)==null?void 0:n[String(t)])==null?void 0:i.iv;return s?{...e,iv:s}:e}createResultFileObject(e,t,s){if(s.appendDataPrefix&&!e.startsWith("data:"))if(t.fileType){let i=it(t.fileType);i.startsWith("plain")||(e=`data:${i};base64,${e}`)}else s.defaultPrefix&&(e=`data:${s.defaultPrefix},${e}`);const n=s.includeUserFileData==!0?{data:e,userFile:t}:{data:e};return s.deliveryMetrics&&(n.deliveryMetrics=s.deliveryMetrics),s.resolvedPreviewId!==void 0&&(n.resolvedPreviewId=s.resolvedPreviewId),n}async getUserFileById(e,t=!1,s=!1,n=null){var C,A;const i=W();let a=0;const r=typeof(e==null?void 0:e.fileId)=="string"&&e.fileId.startsWith("uf_")?e.fileId.slice(3):e==null?void 0:e.fileId;if(await R())try{return await this.getUserFileByIdLocal(r,{includeUserFileData:t,appendDataPrefix:s,defaultPrefix:n})}catch(v){if(await R())throw v;h("File not found locally, fetching from remote:",r)}h("Fetching user file from server:",r);const c=W();let o=!1;try{const v=e.previewId,T=v!=null?`?previewId=${encodeURIComponent(String(v))}`:"",E=await G.instance.remoteRequestRaw(`/userfile/getWithMeta/${encodeURIComponent(String(r))}${T}`,{},{method:"GET"},{headers:{Accept:"multipart/mixed"}});if(!E.ok)throw new Error(`Multipart fetch failed: ${E.status}`);const x=this._parseMultipartBoundary(E.headers.get("content-type"));if(!x)throw new Error("Missing multipart boundary");const q=await E.arrayBuffer();a+=W()-c,o=!0;const z=this._parseMultipartMixed(new Uint8Array(q),x),g=z.find(Q=>(Q.headers["content-type"]||"").toLowerCase().includes("application/json")),b=z.find(Q=>(Q.headers["content-type"]||"").toLowerCase().includes("application/octet-stream"));if(!g||!b)throw new Error("Multipart missing required parts");const P=JSON.parse(new TextDecoder().decode(g.body)),L=P==null?void 0:P.userFile,H=P==null?void 0:P.resolvedPreviewId;if(!(L!=null&&L._id))throw new Error("User file not found (multipart meta)");if((C=L==null?void 0:L.encInfo)!=null&&C.chunked)return await this._readChunkedUserFileResult(L,{appendDataPrefix:s,defaultPrefix:n,includeUserFileData:t});const K=M.ab2str(this._u8ToArrayBuffer(b.body));let Y=K,ne=0;if(L.encInfo){const Q=W(),Ue=await this.userService.getUserRequestContext(),X=await N.instance.getKeyManager(Ue),ie=ze(H,v),pe=await X.decryptObject({data:JSON.stringify(K)},{data:{encrypted:!0,type:"string"}},this._encInfoForRead(L.encInfo,ie)),St=ie!=null&&String(ie)!=="undefined",vt=Number((L==null?void 0:L.fileSize)??0)<=B.CHUNK_THRESHOLD_BYTES;if((pe==null?void 0:pe.decrypted)===!1&&St&&vt)return h("Preview failed to decrypt; re-reading the original",r,v),await this.getUserFileById({...e,previewId:null},t,s,n);Y=pe==null?void 0:pe.data,ne=W()-Q}return this.createResultFileObject(Y,L,{appendDataPrefix:s,defaultPrefix:n,includeUserFileData:t,resolvedPreviewId:H,deliveryMetrics:{source:"remote-multipart",remoteFetchMs:Z(a),decryptMs:Z(ne),remoteTransferredBytes:q.byteLength,totalMs:Z(W()-i)}})}catch(v){o||(a+=W()-c),h("Multipart userfile fetch failed; falling back to binary endpoints",v)}const l=W();let d=!1;try{const v=await S("/userfile/getMetaById",{fileId:r}),T=v==null?void 0:v.userFile;if(!(T!=null&&T._id))throw new Error("User file not found (meta)");if((A=T==null?void 0:T.encInfo)!=null&&A.chunked)return await this._readChunkedUserFileResult(T,{appendDataPrefix:s,defaultPrefix:n,includeUserFileData:t});const E=e.previewId,x=E!=null?`?previewId=${encodeURIComponent(String(E))}`:"",q=await G.instance.remoteRequestRaw(`/userfile/getCiphertext/${encodeURIComponent(String(r))}${x}`,{},{method:"GET"},{headers:{Accept:"application/octet-stream"}});if(!q.ok)throw new Error(`Ciphertext fetch failed: ${q.status}`);const z=await q.arrayBuffer();a+=W()-l,d=!0;const g=M.ab2str(z),b=q.headers.get("X-UserFile-Resolved-Preview-Id"),P=b===null?void 0:b==="original"?null:b;let L=g,H=0;if(T.encInfo){const K=W(),Y=await this.userService.getUserRequestContext(),Q=await(await N.instance.getKeyManager(Y)).decryptObject({data:JSON.stringify(g)},{data:{encrypted:!0,type:"string"}},this._encInfoForRead(T.encInfo,ze(P,E)));L=Q==null?void 0:Q.data,H=W()-K}return this.createResultFileObject(L,T,{appendDataPrefix:s,defaultPrefix:n,includeUserFileData:t,resolvedPreviewId:P,deliveryMetrics:{source:"remote-binary",remoteFetchMs:Z(a),decryptMs:Z(H),remoteTransferredBytes:z.byteLength,totalMs:Z(W()-i)}})}catch(v){d||(a+=W()-l),h("Binary userfile fetch failed; falling back to legacy /userfile/getById",v)}const u=W(),y=await(await G.instance.remoteRequestRaw("/userfile/getById",e)).json();if(a+=W()-u,!(y!=null&&y.results))throw new Error("User file not found");h("getUserFileById response",y);const{userFile:m,fileDataBase64:w,resolvedPreviewId:I}=y.results,U=w;let F=U,_=0;if(m.encInfo){const v=W(),T=await this.userService.getUserRequestContext(),x=await(await N.instance.getKeyManager(T)).decryptObject({data:JSON.stringify(U)},{data:{encrypted:!0,type:"string"}},this._encInfoForRead(m.encInfo,ze(I,e==null?void 0:e.previewId)));F=x==null?void 0:x.data,_=W()-v}return this.createResultFileObject(F,m,{appendDataPrefix:s,defaultPrefix:n,includeUserFileData:t,resolvedPreviewId:I,deliveryMetrics:{source:"remote-legacy",remoteFetchMs:Z(a),decryptMs:Z(_),remoteTransferredBytes:typeof U=="string"?U.length:0,totalMs:Z(W()-i)}})}async getUserFileByIdLocal(e,t){const s=W(),i=await(await ae()).getFileById(e);if(!i)throw new Error("User file not found in local storage");const a={_id:i._id,accountId:null,userId:i.userId,refId:i.refId,refType:i.refType,f
5ilename:i.filename,fileType:i.fileType,fileSize:null,encInfo:i.encInfo,createdAt:i.createdAt?new Date(i.createdAt):null,lastViewedAt:null,deletedAt:null,updatedAt:null,encrypted:!!i.encInfo};let r=i.fileData,c=0;if(i.encInfo){const o=W(),l=await this.userService.getUserRequestContext(),u=await(await N.instance.getKeyManager(l)).decryptObject({data:JSON.stringify(r)},{data:{encrypted:!0,type:"string"}},i.encInfo);r=u==null?void 0:u.data,c=W()-o}return this.createResultFileObject(r,a,{appendDataPrefix:t.appendDataPrefix??!1,defaultPrefix:t.defaultPrefix??"",includeUserFileData:t.includeUserFileData??!1,deliveryMetrics:{source:"account-db",remoteFetchMs:0,decryptMs:Z(c),remoteTransferredBytes:0,totalMs:Z(W()-s)}})}async getLocalFileDataUrl(e){try{const s=await(await ae()).getFileById(e);if(!s)return h("FileService: Local file not found",e),null;let n=s.fileData;if(s.encInfo){const i=await this.userService.getUserRequestContext(),r=await(await N.instance.getKeyManager(i)).decryptObject({data:JSON.stringify(n)},{data:{encrypted:!0,type:"string"}},s.encInfo);n=r==null?void 0:r.data}return n.startsWith("data:")?n:`data:${it(s.fileType)};base64,${n}`}catch(t){return h("FileService: Error getting local file data URL",t),null}}async getStorageQuota(){if("storage"in navigator&&"estimate"in navigator.storage)try{const e=await navigator.storage.estimate(),t=e.usage||0,s=e.quota||0,n=s>0?t/s*100:0;return{used:t,quota:s,percentUsed:n}}catch(e){return h("FileService: Error getting storage quota",e),{used:0,quota:0,percentUsed:0}}return h("FileService: Storage API not available"),{used:0,quota:0,percentUsed:0}}
5async checkStorageQuota(e=80){const t=await this.getStorageQuota();if(t.percentUsed>e){const s=(t.used/1048576).toFixed(2),n=(t.quota/(1024*1024)).toFixed(2);return{warning:!0,message:`Storage is ${t.percentUsed.toFixed(1)}% full (${s}MB / ${n}MB)`,quota:t}}return{warning:!1,quota:t}}async deleteFilesByRefId(e){if(!await R())return h("FileService: deleteFilesByRefId only works in device-only mode"),0;try{const t=await ae(),s=await t.getFilesByRef("item",e);if(s.length>0){const n=s.map(i=>i._id);return await t.userFiles.bulkDelete(n),h("FileService: Deleted files for refId",e,s.length),s.length}return 0}catch(t){return h("FileService: Error deleting files by refId",t),0}}async getAllLocalFiles(){if(!await R())return[];try{return await(await ae()).userFiles.toArray()}catch(e){return h("FileService: Error getting all local files",e),[]}}};k(B,"_staticInstance",null),k(B,"CHUNK_THRESHOLD_BYTES",16*1024*1024),k(B,"DEFAULT_CHUNK_SIZE_BYTES",2*1024*1024),k(B,"DEFAULT_CHUNK_RANGE_BATCH",8),k(B,"MAX_CHUNKED_RECONSTRUCT_BYTES",128*1024*1024),k(B,"PIECES_FROM_BYTES",B.CHUNK_THRESHOLD_BYTES),k(B,"MAX_PIECE_REQUEST_BYTES",4*B.DEFAULT_CHUNK_SIZE_BYTES),k(B,"PIECE_SESSION_IDLE_MS",15*60*1e3);let Re=B;function He(p){if(p===null||typeof p!="object")return p;try{return typeof structuredClone=="function"?structuredClone(p):JSON.parse(JSON.stringify(p))}catch{return p}}function xs(p){const e=typeof p=="string"?p:JSON.stringify(p??"");let t=0;for(let s=0;s<e.length;s++)t=(t<<5)-t+e.charCodeAt(s),t|=0;return Math.abs(t).toString(36)}class _s{constructor(e,t,s=.25,n=500){k(this,"cache",new Map);k(this,"inFlight",new Map);k(this,"active",0);k(this,"queue",[]);this.ttlMs=e,this.maxConcurrent=t,this.jitterFraction=s,this.maxEntries=n}async run(e,t){const s=this.cache.get(e);if(s&&s.expiresAt>Date.now())return He(s.value);const n=this.inFlight.get(e);if(n)return He(await n);const i=(async()=>{await this.acquire();try{const a=await t();return this.store(e,He(a)),a}finally{this.release()}})();this.inFlight.set(e,i);try{return await i}finally{this.inFlight.delete(e)}}invalidate(e){this.cache.delete(e)}clear(){this.cache.clear()}store(e,t){if(!this.cache.delete(e)&&this.cache.size>=this.maxEntries){const a=this.cache.keys().next();a.done||this.cache.delete(a.value)}const n=this.ttlMs*this.jitterFraction,i=this.ttlMs-n+Math.random()*n*2;this.cache.set(e,{value:t,expiresAt:Date.now()+i})}acquire(){return this.active<this.maxConcurrent?(this.active++,Promise.resolve()):new Promise(e=>{this.queue.push(()=>{this.active++,e()})})}release(){this.active--;const e=this.queue.shift();e&&e()}}const bs=3e5,Fs=4,re=class re{constructor(e,t,s){k(this,"contentInfoCache",new _s(bs,Fs));this.encryptionService=e,this.fileService=t,this.itemRepo=s}clearContentInfoCache(){this.contentInfoCache.clear()}static get instance(){return re._staticInstance||(re._staticInstance=new re(Ce.instance,Re.instance,le.instance)),re._staticInstance}getMetaKey(e,t){return t=="URL"?"URL_"+Vt(e):t+"_"+e}async saveTempMeta(e,t,s){if(!e)throw new Error("Invalid URL for meta storage");try{const a=await this.getTempMeta(e);a&&(s={...a,...s})}catch(a){console.error("Error merging existing meta",a)}const n={id:e,metaType:t,timestamp:Date.now(),data:JSON.stringify(s)},i=await ae();if(!i)throw new Error("MetaDataService.saveTempMeta: No current user or accountId available");await i.upsertMetaLookup(n)}async getTempMeta(e){if(!e)throw new Error("Invalid URL for meta storage");const t=await ae();if(!t)throw new Error("MetaDataService.getTempMeta: No current user or accountId available");const s=await t.getMetaLookup(e);
5if(s)try{return{...s,data:typeof s.data=="string"?JSON.parse(s.data):s.data}}catch(n){return console.error("Error parsing meta data",n,s),null}return null}async getImagesFromMetaData(e,t){const s=Wt(e,t)||t,n=[s==null?void 0:s.bannerImageURL,s==null?void 0:s.imageSrc,s==null?void 0:s.googleFaviconSrcPath,s==null?void 0:s.faviconSrcPath].filter(i=>!!i).map(i=>String(i));return h("Image sources",n),await this.getImageFromSourceURLS(n)}async getImageFromSourceURLS(e){h("Image sources",e);for(let t of e){h("Trying to load image",t);try{let s;try{s=await Bt(t)}catch(i){console.error("Failed to load image directly from src",i)}if(!s&&!await R())try{console.error("Failed to load image directly from src, trying proxy");let i="/userdata/proxy?url="+encodeURIComponent(t);s=await(await G.instance.remoteRequestRaw(i,{},{method:"GET"})).blob()}catch(i){throw console.error("Failed to load image from proxy",i),i}if(!s){console.error("Failed to load image, skipping");continue}return{image:await Kt({imageBlob:s,maxSize:800,quality:.7}),imageSrc:t}}catch(s){console.error("Failed to load metadata, image ",t,s)}}return{image:null,imageSrc:null}}static async getImageFromURL(e){}async fetchMetadata(e,t={}){if(!e)return{success:!1,meta:null,subType:null,image:null,imageSrc:null,error:"No URL provided"};try{const{meta:s,image:n}=await this.getMetaAndBannerByURL(e,{skipBanner:t.skipBanner??!1,force:t.force??!1});if(!s)return{success:!1,meta:null,subType:null,image:null,imageSrc:null,error:"Failed to fetch metadata"};const i=ts(s,e);return{success:!0,meta:s,subType:i,image:n??null,imageSrc:s.bannerImageSrcPath??null}}catch(s){return console.error("fetchMetadata error:",s),{success:!1,meta:null,subType:null,image:null,imageSrc:null,error:s instanceof Error?s.message:"Unknown error"}}}async fetchAndPersistMetadata(e,t,s,n={}){var d,u,f,y;const i=await this.fetchMetadata(t,n);if(!i.success||!i.meta)return i;let a=i.meta,r=null,c=null;try{c=await this.itemRepo.getItemById(e);const m=(d=c==null?void 0:c.details)==null?void 0:d.meta;m&&typeof m=="object"&&!Array.isArray(m)&&(a=this.mergeMetaPreservingExisting(m,i.meta)),r=this.mergeInfoPreservingExisting((u=c==null?void 0:c.details)==null?void 0:u.info,i.meta,n.mergeDiscoveredFeeds===!0)}catch(m){console.warn("MetaDataService.fetchAndPersistMetadata: failed to merge existing meta",m)}await this.saveMetaAndImage(e,s,a,i.image,r);const o=n.currentType??((f=c==null?void 0:c.details)==null?void 0:f.type)??null,l=n.currentSubType??((y=c==null?void 0:c.details)==null?void 0:y.subType)??null;if(n.updateSubType&&ss({currentType:o,currentSubType:l,derivedSubType:i.subType})){const m={subType:i.subType};m.type="link";const w={...m,encInfo:s};await R()?await this.itemRepo.updateItemLocal(e,m):await S("/item/update",{itemId:e,data:w})}return i}mergeMetaPreservingExisting(e,t){return zt(e,t)}mergeInfoPreservingExisting(e,t,s=!1){return s?as(e,t):e&&typeof e=="object"?{...e}:e||null}async persistProvidedMetaAndImage(e,t,s,n=null,i={}){var c,o;let a=s,r=null;try{const l=await this.itemRepo.getItemById(e),d=(c=l==null?void 0:l.details)==null?void 0:c.meta;d&&typeof d=="object"&&!Array.isArray(d)&&(a=this.mergeMetaPreservingExisting(d,s)),r=this.mergeInfoPreservingExisting((o=l==null?void 0:l.details)==null?void 0:o.info,s,i.mergeDiscoveredFeeds===!0)}catch(l){console.warn("MetaDataService.persistProvidedMetaAndImage: failed to merge existing meta",l)}await this.saveMetaAndImage(e,t,a,n,r)}async refreshItemMetaIfNeeded(e){return e.url?(await this.fetchAndPersistMetadata(e._id,e.url,e.encInfo,{skipBanner:!0,updateSubType:!1})).success:!1}async updateMetaDataForItem(e,t={}){if(!e.url)return!1;const s=await this.fetchAndPersistMetadata(e._id,e.url,e.encInfo,{skipBanner:!1,force:t.force??!1,updateSubType:t.updateSubType??!1});return s.success&&h("MetaData refreshed",s.meta,e),s.success}async saveMetaAndImage(e,t,s,n,i=null){let a={meta:s,encInfo:t};i&&(a.info=i),n&&(a.imageFilename=await this.uploadBannerImageFile(e,t,n)),await R()?await this.itemRepo.updateItemLocal(e,a):await S("/item/update",{itemId:e,data:a})}async uploadBannerImageFile(e,t,s){const{fileData:n,fileType:i}=Nt(s),a=await this.fileService.uploadUserFile({refId:e,refType:"item",fileType:i,encInfo:t,filename:"banner",fileData:n,secure:!0});return await Et("imageCache",a._id),"uf_"+a._id}
5async localizeBannerFromImageBase64(e,t,s){if(!s)return null;const n=await this.uploadBannerImageFile(e,t,s),i={imageFilename:n,encInfo:t};return await R()?await this.itemRepo.updateItemLocal(e,i):await S("/item/update",{itemId:e,data:i}),n}async refreshItemMetaDataForItemIds(e,t=!1,s=!1){if(e.length==0)return!0;let n=[];await R()?n=await this.itemRepo.getItemsByIds(e):n=await S("/item/listByIds",{ids:e}),h("[UIMETA] Items",n);for(const i of n)try{await this.updateMetaDataForItem(i.details,{force:t,updateSubType:s})}catch(a){console.error("Failed to update meta",i.details,a)}return!0}async getDataByURL(e){if(h("getMetaByURL, browser_mode:",D.browser_mode),D.browser_mode)throw new Error("Not implemented");{const t=await qt(e,{timeout:8e3});if(!t.ok)return{base64Data:null};const s=t.headers.get("content-type");return{base64Data:await Ot(await t.blob(),!1),mimeType:s}}}async remoteInfoRequest(e,t,s){return Number.isFinite(s)&&s>0?await G.instance.remoteAPIRequest(e,t,{},{timeout:s}):await S(e,t)}async getResourceInfo(e,t={}){const s=await this.getContentInfo({url:e.url,options:{includeMetadata:!1,includeResourceInfo:!0,includeClassification:!1}},t);return(s==null?void 0:s.resourceInfo)||{rtype:jt.UNKNOWN,meta:null,contentInfo:null}}async getContentInfo(e,t={}){const s=`${e.url}|${JSON.stringify(e.options||{})}|${xs(e.features)}`,n=this.contentInfoCache.run(s,async()=>D.browser_mode&&!await R()?await this.remoteInfoRequest("/data/contentInfo",e,t.timeoutMs):await S("/data/contentInfo",e));if(!(Number.isFinite(t.timeoutMs)&&t.timeoutMs>0))return await n;let i;try{return await Promise.race([n,new Promise((a,r)=>{i=setTimeout(()=>r(new Error(`contentInfo lookup exceeded ${t.timeoutMs}ms`)),t.timeoutMs)})])}finally{i&&clearTimeout(i)}}async getMetaByURL(e,t={}){if(h("getMetaByURL, browser_mode:",D.browser_mode,e),D.browser_mode){if(await R())return null;{const s=await this.getContentInfo({url:e,options:{includeMetadata:!0,includeResourceInfo:!1,includeClassification:!1}},t);return(s==null?void 0:s.meta)||null}}else{const s=await this.getMetaByURLForExtension(e),n=gt(e);if(s&&!n)return s;if(await R())return s||null;const i=await this.getContentInfo({url:e,options:{includeMetadata:!0,includeResourceInfo:!1,includeClassification:!1}},t),a=i==null?void 0:i.meta;return a!=null&&a.title?a:s||a||null}}async getMetaAndBannerByURL(e,t={skipBanner:!1}){let s=await this.getMetaByURL(e);if(!s)return{meta:null,image:null};if(t.skipBanner)return{meta:s,image:null};const{image:n,imageSrc:i}=await this.getImagesFromMetaData(e,s);return s.bannerImageSrcPath=i,{meta:s,image:n}}async getMetaByURLForExtension(e){h("Fetch for extension",e);try{const t=await Us(e);return t!=null&&(t.resolved=!0),t}catch(t){console.error("Error fetching metadata for extension:",t)}return null}static async remoteClientFetch(e){return D.browser_mode&&D.appType!="ios"?await G.instance.remoteRequestRaw("/userdata/proxyr",{url:e,type:"json"}):await fetch(e)}static async getWikiImagesWithQuery(e,t=1){try{let n=`https://commons.wikimedia.org/w/api.php?action=query&format=json&generator=search&gsrsearch=${encodeURIComponent(e)}&gsrlimit=${t}&gsrnamespace=6&prop=imageinfo&iiprop=url`;const r=(await(await re.remoteClientFetch(n)).json()).query.pages;let c=[];for(const o in r)if(r.hasOwnProperty(o)){const u=r[o].imageinfo[0].url;c.push(u)}return c}catch(s){return console.error("Error getting wiki images",s),[]}}};k(re,"_staticInstance",null);let he=re;ve.instance.addSignoutCallback(()=>{he.instance.clearContentInfoCache()});function ft(p){return p.startsWith("http://")||p.startsWith("https://")}function Es(p){return p.startsWith("uf_")}function As(p){return p.startsWith("data:")}function ht(p){const e=p==null?void 0:p.details;if(!e)return{needs:!1};if(e.published)return{needs:!1};if(e.encrypted&&!e.encInfo)return{needs:!1};const t=typeof e.imageFilename=="string"?e.imageFilename.trim():"";if(t)return Es(t)?{needs:!1}:As(t)?{needs:!1}:ft(t)?{needs:!0,source:"remoteImageFilename",remoteUrl:t}:{needs:!1};const s=rs(e.meta,e.url??void 0).find(ft);return s?{needs:!0,source:"meta",remoteUrl:s}:{needs:!1}}const $e="itemBannerLocalize:failed",Ts=3,ks=3,Ms=200,fe=class fe{constructor(){k(this,"queue",[]);k(this,"inFlight",new Set);k(this,"activeProcessing",0);k(this,"failedMap",null)}static get instance(){return fe._staticInstance||(fe._staticInstance=new fe),fe._staticInstance}enqueue(e){!e||this.inFlight.has(e)||(this.inFlight.add(e),this.queue.push(e),this.processQueue())}async enqueueLibraryNeedingLocalization(){try{const t=await(await ce.instance.getDataIndex()).itemDataStore.listWhere(n=>ht(n).needs);let s=0;for(const n of t){if(s>=Ms)break;this.enqueue(n.itemId),s++}return h("[BANNER_LOCALIZE] bulk enqueue",{found:t.length,enqueued:s}),s}catch(e){return console.warn("[BANNER_LOCALIZE] bulk enqueue failed",e),0}}processQueue(){for(;this.queue.length>0&&this.activeProcessing<Ts;){const e=this.queue.shift();if(!e)break;this.activeProcessing++,this.localizeItem(e).catch(t=>console.warn("[BANNER_LOCALIZE] localize failed",{itemId:e,error:t})).finally(()=>{this.inFlight.delete(e),this.activeProcessing--,this.processQueue()})}}async localizeItem(e){if(await this.isExhausted(e))return;const t=await le.instance.getItemById(e),s=ht(t);if(!t||!s.needs)return;const n=t.details.encInfo??null;let i=null;try{i=(await he.instance.getImageFromSourceURLS([s.remoteUrl])).image}catch(r){console.warn("[BANNER_LOCALIZE] download failed",{itemId:e,url:s.remoteUrl,e:r})}if(!i){await this.recordFailure(e);return}const a=await he.instance.localizeBannerFromImageBase64(e,n,i);if(!a){await this.recordFailure(e);return}await this.clearFailure(e),h("[BANNER_LOCALIZE] localized",{itemId:e,imageFilename:a}),Ee.emit("item-banner-localized",{itemId:e,imageFilename:a})}async getFailedMap(){return this.failedMap||(this.failedMap=await Be.kvGet($e)??{}),this.failedMap}async isExhausted(e){var s;return(((s=(await this.getFailedMap())[e])==null?void 0:s.attempts)??0)>=ks}async recordFailure(e){var n;const t=await this.getFailedMap(),s=(((n=t[e])==null?void 0:n.attempts)??0)+1;
5t[e]={attempts:s,lastAt:Date.now()},await Be.kvSet($e,t)}async clearFailure(e){const t=await this.getFailedMap();t[e]&&(delete t[e],await Be.kvSet($e,t))}};k(fe,"_staticInstance",null);let Qe=fe;const je=p=>p.replace(/[^a-z0-9]/gi,"_").toLowerCase(),Me=class Me{constructor(e,t,s){k(this,"pendingPieces",new Map);this.encryptionService=e,this.fileService=t,this.itemRepo=s}static get instance(){return this._staticInstance||(this._staticInstance=new Me(Ce.instance,Re.instance,le.instance)),this._staticInstance}async addItemAttachment(e){const{itemId:t,attachmentInfo:s,encInfo:n,existingFileId:i}=e,a=je(s.filename);let r=s.imagePreview?[{data:s.imagePreview,id:"0",type:s.imageType||"jpeg"}]:void 0;const c={ufId:i,refId:t,refType:"item",fileType:s.fileType,encInfo:n,filename:a,fileData:s.fileData,previews:r},o=await this.fileService.uploadUserFile(c);return await this.saveAttachmentEntry(t,s,o,r)}async startAttachmentPieces(e){const{itemId:t,encInfo:s,attachmentInfo:n}=e,i=await this.fileService.startFilePieces({refId:t,refType:"item",fileType:n.fileType,encInfo:s,filename:je(n.filename),fileSize:n.filesize});return this.pendingPieces.set(i.uploadId,{itemId:t,attachmentInfo:n}),i}async finishAttachmentPieces(e){const t=this.pendingPieces.get(e.uploadId);if(!t)throw new Error(Ae);const s=e.imagePreview?[{data:e.imagePreview,id:"0",type:e.imageType||"jpeg"}]:void 0,n=await this.fileService.finishFilePieces({uploadId:e.uploadId,previews:s});this.pendingPieces.delete(e.uploadId);const i=await this.saveAttachmentEntry(t.itemId,t.attachmentInfo,n,s);return{attachmentId:i.attachmentId,fileId:i.fileId}}async saveAttachmentEntry(e,t,s,n){var l,d;const i=je(t.filename),a=n?n.map(u=>({id:u.id,type:u.type})):void 0,r=t.createDate,c={id:i,filename:t.filename,type:t.attachmentType==="snapshot"?"snapshot":"file",...typeof r=="number"?{createDate:r}:{},meta:t.meta,fileType:t.fileType,previews:a,fileId:s._id};if(await R()){const u=await this.itemRepo.getItemById(e),f=(d=(l=u==null?void 0:u.details)==null?void 0:l.attachments)==null?void 0:d.entries,y=Array.isArray(f)?[...f]:[],m=y.findIndex(w=>(w==null?void 0:w.id)===c.id||(w==null?void 0:w.fileId)===c.fileId||(w==null?void 0:w.filename)===c.filename);return m>=0?y[m]={...y[m],...c}:y.push(c),await this.itemRepo.updateItemLocal(e,{attachments:{entries:y}}),{attachmentId:c.id,fileId:c.fileId}}const o=await this.encryptionService.remoteRequestEncryptionWrapper("/item/attachment/add",{itemId:e,attachment:c});return{attachmentId:c.id,fileId:c.fileId,url:o==null?void 0:o.url}}};k(Me,"_staticInstance",null);let Je=Me;const Le=class Le{constructor(e,t,s){this.authService=e,this.userService=t,this.indexService=s}parseDateMs(e){if(typeof e!="string"||e.length===0)return 0;const t=Date.parse(e);return Number.isFinite(t)?t:0}getCreatedAtMs(e){var t,s;return Math.max(this.parseDateMs((t=e==null?void 0:e.details)==null?void 0:t.createdAt),this.parseDateMs((s=e==null?void 0:e.details)==null?void 0:s.updatedAt),0)}getLastTouchedAtMs(e){var t,s,n,i;return Math.max(this.parseDateMs((t=e==null?void 0:e.feedback)==null?void 0:t.lastVisit),this.parseDateMs((s=e==null?void 0:e.feedback)==null?void 0:s.updatedAt),this.parseDateMs((n=e==null?void 0:e.details)==null?void 0:n.updatedAt),this.parseDateMs((i=e==null?void 0:e.details)==null?void 0:i.createdAt),0)}getSortTime(e){const t=e.sortTime;return typeof t=="number"?t:0}static get instance(){return this._staticInstance||(this._staticInstance=new Le(Ge.instance,ye.instance,ce.instance)),this._staticInstance}async rediscoverQueue(e){let{timeFrameDays:t=7,showReadLater:s=!1,showCollections:n=!1}=e;const i=await this.indexService.getDataIndex(),a=60*60*24*t,r=new Date().getTime(),c=await i.itemDataStore.listWhere(o=>{const l=o==null?void 0:o.details;if(!n&&(l==null?void 0:l.type)=="col")return!1;const d=o==null?void 0:o.feedback;if((d==null?void 0:d.archivedDate)!=null||(d==null?void 0:d.neverRemindDate)!=null)return!1;const u=(l==null?void 0:l.createdAt)||(l==null?void 0:l.updatedAt);if(d){if((d==null?void 0:d.isReadLaterDate)!=null&&!s)return!1;let f=new Date((d==null?void 0:d.lastVisit)||0).getTime()+a,y=new Date((d==null?void 0:d.snoozeUntilDate)||0).getTime(),m=Math.max(f,y);return o.sortTime=m,r-m>0}else if(u){const f=new Date(u).getTime()+a;return o.sortTime=f,r-f>0}else return!0});return c.sort((o,l)=>o.sortTime-l.sortTime),c.slice(0,200)}async cleanupCandidates(e){const{limit:t=100,minItemAgeDays:s=180,minSinceTouchedDays:n=120,includeCollections:i=!1,includeReadLater:a=!1,includeStarred:r=!1,onlyKept:c=!1}=e||{},o=await this.indexService.getDataIndex(),l=Date.now(),d=Math.max(0,Math.round(s))*24*60*60*1e3,u=Math.max(0,Math.round(n))*24*60*60*1e3,f=await o.itemDataStore.listWhere(y=>{const m=y==null?void 0:y.details,w=y==null?void 0:y.feedback;if(!m||!i&&m.type==="col"||(w==null?void 0:w.archivedDate)!=null||(w==null?void 0:w.isHidden)===!0||!a&&(w==null?void 0:w.isReadLaterDate)!=null||!r&&(w==null?void 0:w.starredDate)!=null)return!1;if(c){if((w==null?void 0:w.keepFromCleanupDate)==null)return!1}else if((w==null?void 0:w.keepFromCleanupDate)!=null)return!1;const I=this.getCreatedAtMs(y);if(d>0&&I>0&&l-I<d)return!1;const U=this.getLastTouchedAtMs(y);return u>0&&U>0&&l-U<u?!1:(y.sortTime=U||I||l,!0)});return f.sort((y,m)=>this.getSortTime(y)-this.getSortTime(m)),f.slice(0,Math.max(1,t))}async readLaterFeed(e){const{limit:t=500,showCollections:s=!0,hideArchived:n=!0,hideHidden:i=!0,includeSnoozed:a=!1}=e,r=await this.indexService.getDataIndex(),c=Date.now(),o=await r.itemDataStore.listWhere(l=>{const d=l==null?void 0:l.details,u=l==null?void 0:l.feedback;if(!(u!=null&&u.isReadLaterDate)||!s&&(d==null?void 0:d.type)==="col"||n&&(u==null?void 0:u.archivedDate)!=null||i&&(u==null?void 0:u.isHidden)===!0)return!1;const f=this.parseDateMs(u==null?void 0:u.snoozeUntilDate);return!a&&f>c?!1:(l.sortTime=this.parseDateMs(u.isReadLaterDate),l.sortTime<=0&&(l.sortTime=Math.max(this.parseDateMs(d==null?void 0:d.updatedAt),this.parseDateMs(d==null?void 0:d.createdAt))),!0)});return o.sort((l,d)=>this.getSortTime(d)-this.getSortTime(l)),o.slice(0,Math.max(1,t))}};k(Le,"_staticInstance",null);let Xe=Le;const Ls="publish-blind-index-v1",Ds="kindredly-publish-blind-index-v1",Ps="v1:",Ze=new TextEncoder;function Bs(p){const e=new Uint8Array(p);let t="";for(let s=0;s<e.length;s++)t+=e[s].toString(16).padStart(2,"0");return t}async function Ks(p){const e=await crypto.subtle.importKey("raw",p,"HKDF",!1,["deriveKey"]);return await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:Ze.encode(Ds),info:Ze.encode(Ls)},e,{name:"HMAC",hash:"SHA-256",length:256},!1,["sign"])}async function Ns(p,e){const t=await crypto.subtle.sign("HMAC",p,Ze.encode(Ps+e));return Bs(t)}const pt=new Map;async function Os(){try{const{UserService:p}=await Ve(async()=>{const{UserService:o}
5=await import("./OperationQueueKzEpmh-u.js").then(l=>l.aQ);return{UserService:o}},__vite__mapDeps([3,4,5,6,7,1,8,9,10,11,12,2,13,14])),{EncryptionKeyService:e}=await Ve(async()=>{const{EncryptionKeyService:o}=await import("./OperationQueueKzEpmh-u.js").then(l=>l.aP);return{EncryptionKeyService:o}},__vite__mapDeps([3,4,5,6,7,1,8,9,10,11,12,2,13,14])),t=await p.instance.getUserRequestContext(null),s=t==null?void 0:t.accountId;if(!s)return null;const n=pt.get(s);if(n)return n;const i=await e.instance.getKeyManager(t);if(!i)return null;const a=await i.getAcntSecretKey();if(!(a!=null&&a.key))return null;const r=await crypto.subtle.exportKey("raw",a.key),c=await Ks(r);return pt.set(s,c),c}catch(p){return h("[BlindIndex] failed to derive account index key",p),null}}async function qs(p){if(!p)return null;const e=await Os();return e?Ns(e,p):null}const wt=Tt.plus.library.legacyMaxItemsPerCollection,De=class De{constructor(e,t,s,n,i,a){this.userService=e,this.encryptionService=t,this.indexService=s,this.itemService=n,this.localItemRepo=i,this.remoteRequester=a}static get instance(){return this._staticInstance||(this._staticInstance=new De(ye.instance,Ce.instance,ce.instance,et.instance,le.instance,G.instance)),this._staticInstance}async collectionItems(e,t={}){var i;const s=((i=await At())==null?void 0:i.offlineFallbackEnabled)===!0,n=async()=>{const a=await this.userService.getCurrentUserId(),r=e.userId||a,c=await this.indexService.getDataIndex(r);h("ItemCollectionService.collectionItems: LOCAL FALLBACK START",e.collectionId);const o=await c.itemRelationStore.getItemIdsForCollection(e.collectionId);if(o.length===0)return[];let l=await c.itemDataStore.getManyByIds(o);e.typeFilter&&(l=l.filter(I=>{var U;return((U=I.details)==null?void 0:U.type)===e.typeFilter}));const d=await c.itemRelationStore.getRelationsForCollection(e.collectionId),u=new Map(d.map(I=>[I.itemId,I.order])),f=l.sort((I,U)=>{const F=u.get(I.itemId)??0,_=u.get(U.itemId)??0;return F-_}),m=(await this.userService.listAccountUsersWithCache()).map(I=>({userId:I._id,permission:me.viewer,user:{_id:I._id,username:I.username,displayedName:I.displayedName,profileImage:I.profileImage},permissionDetails:{direct:!0}})),w=m.find(I=>I.userId===a);for(const I of f)I.permissions=m,I.details.permissionUserId=a,I.details.permission=w==null?void 0:w.permission;return f};if(await R()){const a=await this.userService.getCurrentUserId(),r=e.userId||a,c=await this.indexService.getDataIndex(r);h("ItemCollectionService.collectionItems: START",e.collectionId);const o=await c.itemRelationStore.getItemIdsForCollection(e.collectionId);if(h("ItemCollectionService.collectionItems: Got itemIds",o),o.length===0)return h("ItemCollectionService.collectionItems: No items found, returning empty array"),[];let l=await c.itemDataStore.getManyByIds(o);e.typeFilter&&(l=l.filter(w=>{var I;return((I=w.details)==null?void 0:I.type)===e.typeFilter})),h("ItemCollectionService.collectionItems: Fetched items",l.length);const d=await c.itemRelationStore.getRelationsForCollection(e.collectionId),u=new Map(d.map(w=>[w.itemId,w.order])),f=l.sort((w,I)=>{const U=u.get(w.itemId)??0,F=u.get(I.itemId)??0;return U-F}),y=await this.itemService.defaultPermsForLocalMode(),m=y.find(w=>w.userId===a);for(const w of f)w.permissions=y,w.details.permissionUserId=a,w.details.permission=m==null?void 0:m.permission;return f}try{return await S("/collection/items",{userId:e.userId,collectionId:e.collectionId,typeFilter:e.typeFilter},{forceRefresh:t==null?void 0:t.forceRefresh})}catch(a){if(!s)throw a;return typeof navigator<"u"&&navigator.onLine===!1?await n():await n()}}async createCollection(e){if(await R())return await this.localItemRepo.createCollection(e);const t=await S("/collection/create",e);return await this.indexService.updateDataIndex(),t}async createShowcaseCollection(e){var u;if(await R())throw new Error("Showcase collection is not supported in local mode yet");const t=await this.userService.getUserRequestContext(),s=!e||e===t.userId,n=async()=>await S("/collection/showcase/create",{userId:e,details:{name:"Showcase",description:null,subType:"defaultShowcaseCollection",permanent:!0},options:{skipNotifications:!0}}),i=f=>{const y=f==null?void 0:f.details;if(!y||typeof y!="object")return!1;if(y.decrypted===!1)return!0;const m=y.name;return typeof m=="string"&&m.startsWith('"')&&/[A-Za-z0-9+/_-]{16,}/.test(m)},a=async f=>{if(!s)return f;try{const y=await S("/item/infoById",{itemId:f,targetUserId:t.userId,detailsOnly:!0});return i(y)?(await S("/item/delete",{itemId:f,deleteChildren:!1}),await n()):f}catch{return f}};let r=await n();r=await a(r);const{km:c,wrappingKeyId:o}=await $.instance.ensureGlobalFriendWrappingKey(t),l=await S("/item/infoById",{itemId:r,targetUserId:t.userId,detailsOnly:!0}),d=(u=l==null?void 0:l.details)==null?void 0:u.encInfo;return d&&await $.instance.ensureEncInfoHasWrappingKey({uctx:t,km:c,itemId:r,encInfo:d,wrappingKeyId:o}),await $.instance.ensureGlobalFriendWrappingKeyDeliveredToAllFriends(t),await this.indexService.updateDataIndex(),r}async getShowcaseCollectionId(e){return await R()?null:await S("/collection/showcase/get",{userId:e})||null}async collectionListByUser(e){return await R()?await this._collectionListByUserLocal(e):await this._collectionListByUserRemote(e)}async _collectionListByUserLocal(e){return await this.localItemRepo.listCollections(e.userId)}async _collectionListByUserRemote(e){const{includePath:t,includeParents:s}=e,n=await S("/collection/listByUser",{userId:e.userId});if(h("collectionListByAccount results",[...n]),t)for(const i of n)i.pathItems&&(i.details.path=i.pathItems.map(a=>a==null?void 0:a.name).filter(a=>
5typeof a=="string"&&a.length>0));return n}async addItemToCollections(e){if(await R()){for(const s of e.collectionIds)await this.localItemRepo.addItemToCollection(e.itemId,s);if(e.removeCollectionIds)for(const s of e.removeCollectionIds)await this.localItemRepo.removeItemFromCollection(e.itemId,s);return{}}e.collectionIds&&e.collectionIds.length>0&&await this._ensureParentWrappingKeysIfNeeded(e.itemId,e.collectionIds,e.tempAuthToken);const t=await S("/item/addToCollections",e);return e.tempAuthToken||await this._recordMembershipOnDevice(e.itemId,e.collectionIds||[],e.removeCollectionIds||[]),t}async _recordMembershipOnDevice(e,t,s){try{const n=(await this.indexService.getDataIndex()).itemRelationStore,i=await n.getRelationsForItem(e),a=new Set(s);i.some(o=>a.has(o.collectionId))&&(await n.deleteRelationsForItem(e),await n.update(i.filter(o=>!a.has(o.collectionId))));const r=i.filter(o=>!a.has(o.collectionId)).map(o=>o.collectionId),c=await this.userService.getCurrentUserId()||void 0;for(const o of t)r.includes(o)||(await n.addRelation({collectionId:o,itemId:e,order:r.length,userId:c}),r.push(o))}catch(n){console.warn("[ItemCollectionService] Could not record the collection change on the device:",(n==null?void 0:n.message)||n)}}async _ensureItemAndAttachmentsHaveWrappingKey(e){var y,m,w,I,U,F,_,C,A;const{uctx:t,km:s,itemId:n,wrappingKeyId:i,promoteCollectionsToNetwork:a}=e;if(!s)throw new Error("Encryption not available (no KeyManager)");const r=await S("/item/infoById",{itemId:n,targetUserId:t.userId,detailsOnly:!0}),c=$.instance.getGlobalFriendWrappingKeyId(t.accountId);if(i===c){const v=(y=r==null?void 0:r.details)==null?void 0:y.userId,T=new Set((await this.userService.listAccountUsersWithCache()).map(E=>E==null?void 0:E._id).filter(E=>typeof E=="string"&&E.length>0));if(v&&!T.has(v))return h("[Showcase] Skip adding global-friend unwrap entry (not in account)",{itemId:n,ownerUserId:v,accountId:t.accountId,uctxUserId:t.userId}),null}const o=(m=r==null?void 0:r.details)==null?void 0:m.encInfo;if(!o)return null;const l=((w=r==null?void 0:r.details)==null?void 0:w.type)==="col";a&&l&&((I=r==null?void 0:r.details)==null?void 0:I.visibility)!=="network"&&await S("/item/update",{itemId:n,data:{visibility:"network"},skipEncUpdate:!0}),await $.instance.ensureEncInfoHasWrappingKey({uctx:t,km:s,itemId:n,encInfo:o,wrappingKeyId:i});const d=v=>typeof v!="string"||v.length===0||v.startsWith("http")?null:v.startsWith("uf_")?v.slice(3):v.startsWith("file_")?v:null,u=d((U=r==null?void 0:r.details)==null?void 0:U.imageFilename);if(u){const v=await S("/userfile/getMetaById",{fileId:u}),T=(F=v==null?void 0:v.userFile)==null?void 0:F.encInfo;T&&await $.instance.ensureUserFileEncInfoHasWrappingKey({uctx:t,km:s,fileId:u,encInfo:T,wrappingKeyId:i})}const f=((C=(_=r==null?void 0:r.details)==null?void 0:_.attachments)==null?void 0:C.entries)||[];for(const v of f){const T=d(v==null?void 0:v.fileId)||(v==null?void 0:v.fileId);if(!T)continue;const E=await S("/userfile/getMetaById",{fileId:T}),x=(A=E==null?void 0:E.userFile)==null?void 0:A.encInfo;x&&await $.instance.ensureUserFileEncInfoHasWrappingKey({uctx:t,km:s,fileId:T,encInfo:x,wrappingKeyId:i})}return{isCollection:l}}async _ensureWrappingKeyForCollectionContents(e){const{uctx:t,km:s,collectionId:n,wrappingKeyId:i,depth:a,maxDepth:r}=e;if(a>r)return;const o=(await S("/collection/items",{collectionId:n,userId:t.userId})||[]).slice(0,wt);for(const l of o){const d=(l==null?void 0:l.itemId)||l._id;if(d)try{const u=await this._ensureItemAndAttachmentsHaveWrappingKey({uctx:t,km:s,itemId:d,wrappingKeyId:i,promoteCollectionsToNetwork:!0});u!=null&&u.isCollection&&await this._ensureWrappingKeyForCollectionContents({uctx:t,km:s,collectionId:d,wrappingKeyId:i,depth:a+1,maxDepth:r})}catch{}}}_getWrappingKeyIdsFromEncInfo(e){if(!e||!("keys"in e)||!e.keys)return[];const t=e.keys.map(s=>s==null?void 0:s.wrappingKeyId).filter(s=>typeof s=="string"&&s.length>0);return Array.from(new Set(t))}async getAdditionalWrappingKeyIdsForDirectChildWrite(e){var a,r;const t=Array.from(new Set((e.parentCollectionIds||[]).filter(c=>typeof c=="string"&&c.length>0)));if(t.length===0||await R())return{wrappingKeyIds:[],includesShowcase:!1};const s=await S("/collection/listByIds",{ids:t,userId:e.userId||void 0,tempAuthToken:e.tempAuthToken}),n=new Set;let i=!1;for(const c of s||[]){((a=c==null?void 0:c.details)==null?void 0:a.subType)==="defaultShowcaseCollection"&&(i=!0);for(const o of this._getWrappingKeyIdsFromEncInfo((r=c==null?void 0:c.details)==null?void 0:r.encInfo))n.add(o)}if(i){const c=await this.userService.getUserRequestContext(e.userId||null),{wrappingKeyId:o}=await $.instance.ensureGlobalFriendWrappingKey(c);n.add(o)}return{wrappingKeyIds:Array.from(n),includesShowcase:i}}async _ensureItemAndAttachmentsHaveWrappingKeys(e){var I,U,F,_,C,A,v,T,E;const{uctx:t,km:s,itemId:n,wrappingKeyIds:i,promoteCollectionsToNetwork:a}=e;if(!s)throw new Error("Encryption not available (no KeyManager)");const r=await S("/item/infoById",{itemId:n,targetUserId:t.userId,detailsOnly:!0}),c=$.instance.getGlobalFriendWrappingKeyId(t.accountId),o=(I=r==null?void 0:r.details)==null?void 0:I.userId;let l=null;i.includes(c)&&(l=new Set((await this.userService.listAccountUsersWithCache()).map(x=>x==null?void 0:x._id).filter(x=>
5typeof x=="string"&&x.length>0)));const u=(U=r==null?void 0:r.details)==null?void 0:U.encInfo;if(!u)return null;const f=((F=r==null?void 0:r.details)==null?void 0:F.type)==="col";a&&f&&((_=r==null?void 0:r.details)==null?void 0:_.visibility)!=="network"&&await S("/item/update",{itemId:n,data:{visibility:"network"},skipEncUpdate:!0});for(const x of i)try{if(x===c&&o&&l&&!l.has(o))continue;await $.instance.ensureEncInfoHasWrappingKey({uctx:t,km:s,itemId:n,encInfo:u,wrappingKeyId:x})}catch{}const y=x=>typeof x!="string"||x.length===0||x.startsWith("http")?null:x.startsWith("uf_")?x.slice(3):x.startsWith("file_")?x:null,m=y((C=r==null?void 0:r.details)==null?void 0:C.imageFilename);if(m){const x=await S("/userfile/getMetaById",{fileId:m}),q=(A=x==null?void 0:x.userFile)==null?void 0:A.encInfo;if(q)for(const z of i)try{await $.instance.ensureUserFileEncInfoHasWrappingKey({uctx:t,km:s,fileId:m,encInfo:q,wrappingKeyId:z})}catch{}}const w=((T=(v=r==null?void 0:r.details)==null?void 0:v.attachments)==null?void 0:T.entries)||[];for(const x of w){const q=y(x==null?void 0:x.fileId)||(x==null?void 0:x.fileId);if(!q)continue;const z=await S("/userfile/getMetaById",{fileId:q}),g=(E=z==null?void 0:z.userFile)==null?void 0:E.encInfo;if(g)for(const b of i)try{await $.instance.ensureUserFileEncInfoHasWrappingKey({uctx:t,km:s,fileId:q,encInfo:g,wrappingKeyId:b})}catch{}}return{isCollection:f}}async _ensureWrappingKeysForCollectionContents(e){const{uctx:t,km:s,collectionId:n,wrappingKeyIds:i,depth:a,maxDepth:r}=e;if(a>r)return;const o=(await S("/collection/items",{collectionId:n,userId:t.userId})||[]).slice(0,wt);for(const l of o){const d=(l==null?void 0:l.itemId)||l._id;if(d)try{const u=await this._ensureItemAndAttachmentsHaveWrappingKeys({uctx:t,km:s,itemId:d,wrappingKeyIds:i,promoteCollectionsToNetwork:!0});u!=null&&u.isCollection&&await this._ensureWrappingKeysForCollectionContents({uctx:t,km:s,collectionId:d,wrappingKeyIds:i,depth:a+1,maxDepth:r})}catch{}}}async healChildEncryptionKeysToMatchParent(e,t,s={}){var o;if(await R())return{success:!1,message:"Not supported in local mode"};const n=s.uctx||await this.userService.getUserRequestContext(),i=await N.instance.getKeyManager(n,!0);if(!i)return{success:!1,message:"Encryption not available (no KeyManager)"};const a=await S("/item/infoById",{itemId:e,targetUserId:n.userId,detailsOnly:!0}),r=(o=a==null?void 0:a.details)==null?void 0:o.encInfo;if(!r)return{success:!1,message:"Collection is not encrypted (no encInfo)"};const c=this._getWrappingKeyIdsFromEncInfo(r);return c.length===0?{success:!0,maxDepth:(t==null?void 0:t.maxDepth)??1}:(await this._ensureWrappingKeysForCollectionContents({uctx:n,km:i,collectionId:e,wrappingKeyIds:c,depth:0,maxDepth:Math.max(0,(t==null?void 0:t.maxDepth)??1)}),{success:!0,maxDepth:Math.max(0,(t==null?void 0:t.maxDepth)??1)})}async _ensureParentWrappingKeysIfNeeded(e,t,s){const n=await this.userService.getUserRequestContext(),{wrappingKeyIds:i,includesShowcase:a}=await this.getAdditionalWrappingKeyIdsForDirectChildWrite({parentCollectionIds:t,userId:n.userId,tempAuthToken:s});if(i.length===0)return;let r=await N.instance.getKeyManager(n,!0);if(!r)throw new Error("Encryption not available (no KeyManager)");if(a){const{km:o}=await $.instance.ensureGlobalFriendWrappingKey(n);r=o||r}const c=await this._ensureItemAndAttachmentsHaveWrappingKeys({uctx:n,km:r,itemId:e,wrappingKeyIds:i,promoteCollectionsToNetwork:a});c!=null&&c.isCollection&&await this._ensureWrappingKeysForCollectionContents({uctx:n,km:r,collectionId:e,wrappingKeyIds:i,depth:0,maxDepth:3}),a&&await $.instance.ensureGlobalFriendWrappingKeyDeliveredToAllFriends(n)}async repairShowcaseFriendEncryption(e){var r;if(await R())return{success:!1,message:"Showcase encryption repair is not supported in local mode"};const t=await this.userService.getUserRequestContext(e);
5let s=await this.getShowcaseCollectionId(t.userId);s||(s=await this.createShowcaseCollection(t.userId));const{km:n,wrappingKeyId:i}=await $.instance.ensureGlobalFriendWrappingKey(t);try{const c=await S("/item/infoById",{itemId:s,targetUserId:t.userId,detailsOnly:!0}),o=(r=c==null?void 0:c.details)==null?void 0:r.encInfo;o&&await $.instance.ensureEncInfoHasWrappingKey({uctx:t,km:n,itemId:s,encInfo:o,wrappingKeyId:i})}catch{}const a=await S("/collection/items",{collectionId:s,userId:t.userId});for(const c of a||[]){const o=(c==null?void 0:c.itemId)||c._id;if(o)try{const l=await this._ensureItemAndAttachmentsHaveWrappingKey({uctx:t,km:n,itemId:o,wrappingKeyId:i,promoteCollectionsToNetwork:!0});l!=null&&l.isCollection&&await this._ensureWrappingKeyForCollectionContents({uctx:t,km:n,collectionId:o,wrappingKeyId:i,depth:0,maxDepth:3})}catch{}}return await $.instance.ensureGlobalFriendWrappingKeyDeliveredToAllFriends(t),{success:!0,itemCount:(a||[]).length}}async collectionListByIds(e,t){return await R()||!t.forceRefresh?e.ids&&e.ids.length>0?(await this.localItemRepo.listCollections(e.userId)).filter(n=>e.ids.includes(n.itemId)):e.allowListAll?await this.localItemRepo.listCollections(e.userId):[]:await this._collectionListByIdsRemote(e)}async _collectionListByIdsRemote(e){const{includePath:t}=e,n=await S("/collection/listByIds",e)||[];if(h("collectionListByAccount results",[...n]),t)for(const i of n)i!=null&&i.pathItems&&(i.details.path=i.pathItems.map(a=>a==null?void 0:a.name).filter(a=>typeof a=="string"&&a.length>0));return h("collectionListByAccount",n),n}async saveCollectionItemDetails(e){if(await R())return await(await this.indexService.getDataIndex()).itemRelationStore.saveCollectionItemDetails(e.collectionId,e.itemId,e.details,e.order),{};const t=e.details?{...e.details}:void 0,s=await this.encryptionService.remoteRequestEncryptionWrapper("/collection/itemDetails/save",{...e,...t?{details:{...t}}:{}},{dontEncrypt:e.dontEncrypt==!0});try{const n=await this.indexService.getDataIndex();t&&delete t.encInfo,await n.itemRelationStore.saveCollectionItemDetails(e.collectionId,e.itemId,t,e.order)}catch(n){console.warn("[ItemCollectionService] Saved on the server; could not record on the device",n)}return s}async getCollectionInfo(e){if(await R()){const t=e.userId||await this.userService.getCurrentUserId(),s=await this.indexService.getDataIndex(t),n=await s.itemDataStore.getById(e.itemId);if(n){const i=await s.itemRelationStore.getRelationsForItem(e.itemId);n.collectionRelations=i.map(a=>({_id:a._id,collectionId:a.collectionId,order:a.order,createdAt:a.createdAt})),n.collectionIds=i.map(a=>a.collectionId)}return n}return await this.encryptionService.remoteRequestEncryptionWrapper("/item/infoById",e)}};k(De,"_staticInstance",null);let Te=De;const Pe=class Pe{constructor(e,t,s,n,i,a,r,c){this.userService=e,this.encryptionService=t,this.indexService=s,this.metaDataService=n,this.itemAttachmentService=i,this.itemDiscoveryService=a,this.itemRepo=r,this.fileService=c}static get instance(){return this._staticInstance||(this._staticInstance=new Pe(ye.instance,Ce.instance,ce.instance,he.instance,Je.instance,Xe.instance,le.instance,Re.instance)),this._staticInstance}async ensureLocalLibraryMigrationAccess(){const e=await this.userService.getCurrentUser();if(!e||e.type!=="admin")throw new Error("Only admin users can run local library migration")}getNormalizedUrlKey(e){if(!e||typeof e!="string")return null;const t=e.trim();if(!t)return null;try{const s=new URL(t);return s.hostname=s.hostname.toLowerCase(),s.toString()}catch{return t.toLowerCase()}}cloneLocalDetails(e){let t={};try{t=JSON.parse(JSON.stringify(e||{}))}catch{t={...e||{}}}return t==null||delete t.userId,t==null||delete t.accountId,t}async getLocalLibraryImportSummary(e){await this.ensureLocalLibraryMigrationAccess();const t=(e==null?void 0:e.includeRestricted)!==!1,s=Oe("local_account"),n=await s.items.toArray(),i=await s.itemRelations.toArray(),a=t?new Set(["local_admin","local_restricted"]):new Set(["local_admin"]),r=n.filter(u=>{var y;const f=(y=u==null?void 0:u.details)==null?void 0:y.userId;return!f||a.has(f)}),c=new Set(r.map(u=>u.itemId||u._id)),o=r.filter(u=>{var f;return((f=u==null?void 0:u.details)==null?void 0:f.type)==="col"}).length,l=r.filter(u=>{var f;return((f=u==null?void 0:u.details)==null?void 0:f.type)!=="col"}).length,d=i.filter(u=>c.has(u.collectionId)&&c.has(u.itemId));return{sourceCollections:o,sourceItems:l,sourceRelations:d.length,localDataFound:r.length>0}}async clearLocalLibraryData(e){await this.ensureLocalLibraryMigrationAccess();const t=(e==null?void 0:e.includeRestricted)!==!1,s=Oe("local_account"),n=await s.items.toArray(),i=await s.itemRelations.toArray(),a=t?new Set(["local_admin","local_restricted"]):new Set(["local_admin"]),r=new Set(n.filter(o=>{var d;const l=(d=o==null?void 0:o.details)==null?void 0:d.userId;return!l||a.has(l)}).map(o=>o.itemId||o._id)),c=i.filter(o=>r.has(o.collectionId)||r.has(o.itemId)).map(o=>o._id);if(c.length>0&&await s.itemRelations.bulkDelete(c),r.size>0&&await s.items.bulkDelete(Array.from(r)),r.size>0)try{await s.tagIndex.where("itemId").anyOf(Array.from(r)).delete()}catch{}return{clearedItems:r.size,clearedRelations:c.length}}async importLocalLibraryToOnline(e){var z;await this.ensureLocalLibraryMigrationAccess();const t=(e==null?void 0:e.includeRestricted)!==!1,s=(e==null?void 0:e.visibility)||"shared",n=(e==null?void 0:e.skipExactUrlDuplicates)!==!1;await this.indexService.updateDataIndex(!1,!0);const i=Oe("local_account"),a=await i.items.toArray(),r=await i.itemRelations.toArray(),c=t?new Set(["local_admin","local_restricted"]):new Set(["local_admin"]),o=a.filter(g=>{var P;const b=(P=g==null?void 0:g.details)==null?void 0:P.userId;return!b||c.has(b)});if(o.length===0)return{localDataFound:!1,sourceCollections:0,sourceItems:0,importedCollections:0,importedItems:0,skippedDuplicates:0,errors:0};const l=new Map;for(const g of o)l.set(g.itemId||g._id,g);const d=r.filter(g=>l.has(g.collectionId)&&l.has(g.itemId)),u=new Map,f=new Map;for(const g of d){const b=u.get(g.collectionId)||[];b.push({itemId:g.itemId,order:g.order??0}),u.set(g.collectionId,b),f.set(g.itemId,(f.get(g.itemId)||0)+1)}
5for(const[g,b]of u.entries())b.sort((P,L)=>P.order-L.order),u.set(g,b);const y=o.filter(g=>{var b;return((b=g==null?void 0:g.details)==null?void 0:b.type)==="col"}),m=o.filter(g=>{var b;return((b=g==null?void 0:g.details)==null?void 0:b.type)!=="col"}),w=new Set,I=await this.queryFromIndexLocal({urls:[],itemTypes:["item","thing","note","feed","tool","link","video","audio","information"]},{});for(const g of I){const b=this.getNormalizedUrlKey((z=g==null?void 0:g.details)==null?void 0:z.url);b&&w.add(b)}let U=0,F=0,_=0,C=0;const A=new Map,v=new Map;let T=null;try{const g=await S("/collection/create",{details:{name:"Imported Local Library",visibility:s}});T=(g==null?void 0:g.result)||null,T&&(U+=1)}catch(g){console.error("Failed creating import root collection",g),C+=1}const E=async(g,b)=>{var H;const P=v.get(g);if(P){if(b)try{await S("/item/addToCollections",{itemId:P,collectionIds:[b]})}catch(K){console.error("Failed adding imported item to additional collection",K),C+=1}return}const L=l.get(g);if(!(!L||((H=L==null?void 0:L.details)==null?void 0:H.type)==="col"))try{const K=this.cloneLocalDetails(L.details);K.visibility=s,this.normalizeUrlHostnames(K);const Y=this.getNormalizedUrlKey(K==null?void 0:K.url);if(n&&Y&&w.has(Y)){_+=1;return}const ne=await this.saveItem({details:K,collectionIds:b?[b]:null},{skipMetaFetch:!0,dontBlockForMeta:!0});v.set(g,ne.itemId),F+=1,Y&&w.add(Y)}catch(K){console.error("Failed importing local item",g,K),C+=1}},x=async(g,b,P=new Set)=>{var ne,Q,Ue;if(P.has(g))return;P.add(g);const L=A.get(g);if(L)return L;const H=l.get(g);if(!H||((ne=H==null?void 0:H.details)==null?void 0:ne.type)!=="col")return null;let K=null;try{const X=await S("/collection/create",{details:{name:((Q=H==null?void 0:H.details)==null?void 0:Q.name)||"Imported Collection",visibility:s},options:{collectionIds:b?[b]:void 0}});if(K=(X==null?void 0:X.result)||null,!K)return C+=1,null;A.set(g,K),U+=1}catch(X){return console.error("Failed importing collection",g,X),C+=1,null}const Y=u.get(g)||[];for(const X of Y){const ie=l.get(X.itemId);ie&&(((Ue=ie==null?void 0:ie.details)==null?void 0:Ue.type)==="col"?await x(X.itemId,K,P):await E(X.itemId,K))}return K},q=y.map(g=>g.itemId||g._id).filter(g=>(f.get(g)||0)===0);for(const g of q)await x(g,T,new Set);for(const g of y){const b=g.itemId||g._id;A.has(b)||await x(b,T,new Set)}for(const g of m){const b=g.itemId||g._id;(f.get(b)||0)>0||await E(b,T)}for(const g of m){const b=g.itemId||g._id;v.has(b)||await E(b,T)}return await this.indexService.updateDataIndex(!1,!0,!0),Qe.instance.enqueueLibraryNeedingLocalization(),{localDataFound:!0,sourceCollections:y.length,sourceItems:m.length,importedCollections:U,importedItems:F,skippedDuplicates:_,errors:C}}applyRequirementNormalization(e){if(!e.type)return;const t=ns({type:e.type,subType:e.subType,info:e.info});t&&t!==e.subType&&(e.subType=t)}normalizeUrlHostnames(e){if(e.url)try{const t=new URL(e.url);t.hostname=t.hostname.toLowerCase(),e.url=t.toString()}catch{}e.patterns&&Array.isArray(e.patterns)&&(e.patterns=e.patterns.map(t=>{try{if(t.includes("://")){const s=new URL(t.replace("*","placeholder"));return s.hostname=s.hostname.toLowerCase(),s.toString().replace("placeholder","*")}else{const s=t.split("/");return s[0]&&(s[0]=s[0].toLowerCase()),s.join("/")}}catch{return t.toLowerCase()}}))}stampLookupProviderKind(e){const t=os(e==null?void 0:e.url);if(!t)return;const s=Array.isArray(e.kinds)?e.kinds.filter(n=>typeof n=="string"):[];s.includes(t.kindId)||(e.kinds=[...s,t.kindId])}async saveItem(e,t=null){var d,u,f,y,m,w;const s=!(e!=null&&e.itemId);e!=null&&e.details&&(this.normalizeUrlHostnames(e.details),this.applyRequirementNormalization(e.details),s&&this.stampLookupProviderKind(e.details));const n=(d=e==null?void 0:e.details)==null?void 0:d.url,i=(u=e==null?void 0:e.details)!=null&&u.meta?{...(f=e==null?void 0:e.details)==null?void 0:f.meta}:null,a=await R(),r=this.extractPagedTextFromDetails(e==null?void 0:e.details);r&&(e.details.info||(e.details.info={value:""}),e.details.info.value=tt(r),e.details.info.editor||(e.details.info.editor="txt"));let c,o=null,l;if(e.isNew=s,a){const I=await this.itemRepo.saveItemLocal(e,e.targetUserId);c=I.itemId,l=I.feedback}else if(navigator.onLine)try{const I=this.buildServerPayload(e);let U;if(s&&Array.isArray(e.collectionIds)&&e.collectionIds.length>0){const C=await Te.instance.getAdditionalWrappingKeyIdsForDirectChildWrite({parentCollectionIds:e.collectionIds,userId:e.targetUserId,tempAuthToken:e.tempAuthToken});C.wrappingKeyIds.length>0&&(U=C.wrappingKeyIds)}const{result:F,sentData:_}=await this.encryptionService.remoteRequestEncryptionWrapper("/item/save",I,{includeSentDataInResult:!0,additionalWrappingKeyIds:U});if(c=F.itemId,o=(y=_==null?void 0:_.details)==null?void 0:y.encInfo,l=F.feedback,s)try{await this.itemRepo.saveItemLocalWithId(e,c,e.targetUserId)}catch(C){console.warn("Failed to write saved item into the local index",c,C)}}catch(I){throw console.warn("Failed to sync item to server",I),I}else throw new Error("Cannot add item while offline - check internet connection");if(r)try{await this.savePagedTextAttachment({itemId:c,encInfo:o,text:r,existingFileId:void 0,filename:Ke})}catch(I){try{await this.itemRepo.updateItemLocal(c,{info:{...(m=e.details)==null?void 0:m.info,value:r}}),await R()||await S("/item/update",{itemId:c,data:{info:{...(w=e.details)==null?void 0:w.info,value:r}}})}catch{}throw I}if((t==null?void 0:t.dontBlockForMeta)===!0?this.getItemMetadata(s,n,t,e,i,c,o):await this.getItemMetadata(s,n,t,e,i,c,o),!a&&Array.isArray(e.collectionIds)&&e.collectionIds.length>0)try{(await S("/collection/listByIds",{ids:e.collectionIds})||[]).some(F=>{var _;return((_=F==null?void 0:F.details)==null?void 0:_.subType)==="defaultShowcaseCollection"})&&await Te.instance.repairShowcaseFriendEncryption()}catch(I){console.warn("Failed to repair showcase friend encryption after save",I)}return(t==null?void 0:t.includeEncInfo)===!0?{itemId:c,encInfo:o,feedback:l}:{itemId:c,feedback:l}}isPagedTextItemType(e){return e?is(e==null?void 0:e.type,e==null?void 0:e.subType):!1}extractPagedTextFromDetails(e){var n;if(!this.isPagedTextItemType(e))return null;const t=(n=e==null?void 0:e.info)==null?void 0:n.value;if(t==null)return null;const s=typeof t=="string"?t:String(t);return!s||s.trim().length===0?null:s}async savePagedTextAttachment(e){const{base64:t,byteLength:s}=kt(e.text||""),n=e.filename||Ke;await this.itemAttachmentService.addItemAttachment({itemId:e.itemId,attachmentInfo:{filename:n,fileType:"text/plain",fileData:t,filesize:s},encInfo:e.encInfo,existingFileId:e.existingFileId})}
5async tryLoadMarkdownFromUserFileId(e){if(!e)return null;try{const{data:t}=await this.fileService.getUserFileById({fileId:e},!1);if(!t)return null;const s=typeof t=="string"?t:String(t);return Mt(s)}catch{return null}}async loadBodyText(e){var n,i;const t=Ne(e==null?void 0:e.details,0)||Ne(e,0);if(t!=null&&t.fileId){const a=await this.tryLoadMarkdownFromUserFileId(t.fileId);if(a==null)throw new Error("Could not read the note body");return a}const s=(i=(n=e==null?void 0:e.details)==null?void 0:n.info)==null?void 0:i.value;return s==null?"":String(s)}_historyTimeKeyUtc(e){const t=(o,l=2)=>String(o).padStart(l,"0"),s=e.getUTCFullYear(),n=t(e.getUTCMonth()+1),i=t(e.getUTCDate()),a=t(e.getUTCHours()),r=t(e.getUTCMinutes()),c=t(e.getUTCSeconds());return`${s}${n}${i}T${a}${r}${c}Z`}_pageHistoryFilename(e,t){return`page${Number.isFinite(e)?Math.max(0,Math.floor(e)):0}.history.${this._historyTimeKeyUtc(t)}.md`}_parsePageHistoryTimestampMs(e,t){if(!e)return null;const s=Number.isFinite(t)?Math.max(0,Math.floor(t)):0,n=new RegExp(`^page${s}\\.history\\.(\\d{8}T\\d{6}Z)\\.md$`,"i"),i=e.match(n);if(!(i!=null&&i[1]))return null;const a=i[1],r=Number(a.slice(0,4)),c=Number(a.slice(4,6)),o=Number(a.slice(6,8)),l=Number(a.slice(9,11)),d=Number(a.slice(11,13)),u=Number(a.slice(13,15));if(![r,c,o,l,d,u].every(Number.isFinite))return null;const f=Date.UTC(r,c-1,o,l,d,u);return Number.isFinite(f)?f:null}_latestPageHistoryTimestampMs(e,t){var i,a,r;const s=((a=(i=e==null?void 0:e.details)==null?void 0:i.attachments)==null?void 0:a.entries)||((r=e==null?void 0:e.attachments)==null?void 0:r.entries);if(!Array.isArray(s)||s.length===0)return null;let n=null;for(const c of s){const o=typeof(c==null?void 0:c.filename)=="string"?c.filename:"",l=this._parsePageHistoryTimestampMs(o,t);l!=null&&(n==null||l>n)&&(n=l)}return n}async maybeSavePageHistorySnapshot(e){const t=Number.isFinite(e.nowMs)?e.nowMs:Date.now(),s=new Date(t),n=this._latestPageHistoryTimestampMs(e.existingItem,e.pageIndex);if(n!=null){const a=t-n;if(Number.isFinite(a)&&a>=0&&a<5*60*1e3)return}const i=this._pageHistoryFilename(e.pageIndex,s);await this.savePagedTextAttachment({itemId:e.itemId,encInfo:e.encInfo,text:e.text,filename:i})}buildServerPayload(e){var s,n;if(!e.details)throw new Error("SaveItemRequest must have details object");const t={itemId:e.itemId,details:{...e.details},isNew:e.isNew,collectionIds:e.collectionIds,bannerQuery:e.bannerQuery,removeMissingCollections:e.removeMissingCollections,quickShareUserIds:e.quickShareUserIds,accessRequestId:e.accessRequestId,feedbackUpdate:e.feedbackUpdate,notifyOthers:e.notifyOthers,options:e.options,targetUserId:e.targetUserId,tempAuthToken:e.tempAuthToken};return(s=t.collectionIds)!=null&&s.length||delete t.collectionIds,(n=t.quickShareUserIds)!=null&&n.length||delete t.quickShareUserIds,t.bannerQuery||delete t.bannerQuery,t.removeMissingCollections||delete t.removeMissingCollections,t.accessRequestId||delete t.accessRequestId,t.feedbackUpdate||delete t.feedbackUpdate,t.options||delete t.options,t.targetUserId||delete t.targetUserId,t.tempAuthToken||delete t.tempAuthToken,t.isNew||delete t.isNew,t}async getItemMetadata(e,t,s,n,i,a,r){var u,f,y,m,w,I;if(!e||(s==null?void 0:s.skipMetaFetch)===!0){this.indexService.updateDataIndex();return}if(!t&&n.bannerQuery){await this.handleBannerQuery(n.bannerQuery,a,r,i),this.indexService.updateDataIndex();return}if(!t){this.indexService.updateDataIndex();return}let c=(s==null?void 0:s.forceMeta)||!1;if(gt(t)&&!((u=i==null?void 0:i.tsManifest)!=null&&u.mediaMetadata)&&(c=!0),!(i!=null&&i.tsExtractedInfo)){const U=Yt(t);((U?!1:Gt(t))||U)&&(c=!0)}const l=((f=i==null?void 0:i.tsExtractedInfo)==null?void 0:f.sourceId)==="live_dom";if(!c&&!l&&((y=n==null?void 0:n.details)!=null&&y.imageFilename)&&i){h("Already have metadata and image, persisting merged metadata info"),await this.metaDataService.persistProvidedMetaAndImage(a,r,i,null,{mergeDiscoveredFeeds:s==null?void 0:s.mergeDiscoveredFeeds}),this.indexService.updateDataIndex();return}if(!c&&!l&&!((m=n==null?void 0:n.details)!=null&&m.imageFilename)&&i){h("Getting image from existing meta data");const{image:U,imageSrc:F}=await this.metaDataService.getImagesFromMetaData(t,i);i.imageSrc=F,await this.metaDataService.persistProvidedMetaAndImage(a,r,i,U,{mergeDiscoveredFeeds:s==null?void 0:s.mergeDiscoveredFeeds}),this.indexService.updateDataIndex();return}h("Fetching full metadata for item",a,t);const d=await this.metaDataService.fetchAndPersistMetadata(a,t,r,{skipBanner:!1,force:c,updateSubType:!0,mergeDiscoveredFeeds:s==null?void 0:s.mergeDiscoveredFeeds,currentType:((w=n==null?void 0:n.details)==null?void 0:w.type)??null,currentSubType:((I=n==null?void 0:n.details)==null?void 0:I.subType)??null});d.success?h("Metadata fetched successfully",d.meta,d.subType):console.warn(`Metadata fetch failed for item ${a}:`,d.error),this.indexService.updateDataIndex()}async handleBannerQuery(e,t,s,n){h("Getting image from wiki",e);const i=await he.getWikiImagesWithQuery(e);if(h("Got image from wiki",i),i.length>0){const{image:a,imageSrc:r}=await this.metaDataService.getImageFromSourceURLS([i[0]]),c=n??{};c.imageSrc=r,await this.metaDataService.saveMetaAndImage(t,s,c,a)}}async listAllItemIds(){const e=await this.userService.getCurrentUserId();return(await this.indexService.getDataIndex(e)).itemDataStore.listAllIds()}async getItemsByIdsLocal(e){const t=await this.userService.getCurrentUserId();return(await this.indexService.getDataIndex(t)).itemDataStore.getManyByIds(e)}async getItemIdsByTags(e){if(!(e!=null&&e.length))return[];const t=await this.userService.getCurrentUserId();return(await this.indexService.getDataIndex(t)).itemDataStore.getIdsByTagsIgnoreCase(e)}async getItemIdsByKinds(e){if(!(e!=null&&e.length))return[];const t=await this.userService.getCurrentUserId();return(await this.indexService.getDataIndex(t)).itemDataStore.getIdsByKinds(e)}async getFacetCounts(e){const t=await this.userService.getCurrentUserId(),s=await this.indexService.getDataIndex(t);return e==="status"?s.itemDataStore.countBy(n=>n.details?cs(n):null):s.itemDataStore.countBy(n=>!n.details||n.details.archived?null:e==="usage"?ot(n.details.useCriteria):ct(n.details))}async getLibraryAppItemsLocal(){const e=await this.userService.getCurrentUserId();return(await(await this.indexService.getDataIndex(e)).itemDataStore.findByType("thing")).filter(n=>{var i;return((i=n==null?void 0:n.details)==null?void 0:i.subType)==="kin_app"||!!es(n)})}async getItemsWithInfo(e={},t={}){const s=e.userId||await this.userService.getCurrentUserId(),n=e.ids&&e.ids.length>0?e.ids:null,i=await R(),a=t.forceRefresh===!0,r=await this.indexService.getDataIndex(s);if(n){if(a&&!i&&navigator.onLine)try{const l=await S("/item/listByIds",{ids:n,userId:s});return l.length>0&&await this.itemRepo.storeItems(l,s),l}catch(l){console.warn("Failed to force-refresh items from remote",l)}let o=await this.itemRepo.getItemsByIds(n,s);if(!i&&navigator.onLine){const l=new Set(o.map(u=>u.itemId)),d=n.filter(u=>!l.has(u));if(d.length>0)try{const u=await S("/item/listByIds",{ids:d,userId:s});u.length>0&&(await this.itemRepo.storeItems(u,s),o=await this.itemRepo.getItemsByIds(n,s))}catch(u){console.warn("Failed to fetch missing items from remote",u)}}return o}const c=await r.itemDataStore.listAll();return t.forceRefresh&&!i&&navigator.onLine&&this.indexService.updateDataIndex(),c}async getItemInfoById(e,t){const{itemId:s,userId:n}=e,i=await this.userService.getCurrentUserId(),a=n||await this.userService.getCurrentUserId(),r=await R();t.forceRefresh;const c=t.localOnly===!0;if(r||c||!navigator.onLine){const o=await this.itemRepo.getItemById(s,a);if(o){if(r){o.permissions=await this.defaultPermsForLocalMode();const u=o.permissions.find(f=>f.userId===i);o.details.permissionUserId=i,o.details.permission=u.permission}const d=await(await this.indexService.getDataIndex(a)).itemRelationStore.getRelationsForItem(e.itemId);return o.collectionRelations=d.map(u=>
5({_id:u._id,collectionId:u.collectionId,order:u.order,createdAt:u.createdAt})),o.collectionIds=d.map(u=>u.collectionId),o}}if(c)return null;try{const o=await S("/item/infoById",e);if(o)return await this.itemRepo.storeItems([o],a),o}catch(o){return console.warn(`Failed to fetch item ${s} from remote`,o),await this.itemRepo.getItemById(s,a)}return null}async getItemByPubOrSubId(e,t){const s=await R(),n=e.targetUserId||null;if(s)try{const a=await(await this.indexService.getDataIndex()).itemDataStore.listWhere(r=>{var c,o;return((c=r.details)==null?void 0:c.publishId)===e.publishId&&(!n||((o=r.details)==null?void 0:o.userId)===n)});return a.length>0?a:null}catch(i){return console.warn(`Failed to query local items for pub/sub id ${e.publishId}`,i),null}try{let i=e;if(await ls("publishPrivacy"))try{const r=await qs(e.publishId);r&&(i={...e,publishIdBlindKey:r})}catch(r){h("[ItemService] blindKey compute failed; querying by publishId only",r)}return await S("/item/findWithPublishId",i)}catch(i){return console.warn(`Failed to fetch items for pub/sub id ${e.publishId}`,i),null}}async deleteItem(e){if(await R()){await this.fileService.deleteFilesByRefId(e.itemId),await this.itemRepo.deleteItemLocal(e);return}await S("/item/delete",e),this.indexService.updateDataIndex()}async getUserItemsWithInfo(e,t=!0,s=null,n=!1){if(!e||e.length==0)return[];const i=s||await this.userService.getCurrentUserId(),a=await R();let r=await this.itemRepo.getItemsByIds(e,i);const c=new Set(r.map(l=>l.itemId)),o=e.filter(l=>!c.has(l));if(o.length>0&&!a&&navigator.onLine)try{const l=await S("/item/listByIds",{ids:o,includeFeedback:!0});l.length>0&&(await this.itemRepo.storeItems(l,i),r=await this.itemRepo.getItemsByIds(e,i))}catch(l){console.warn("Failed to fetch missing items from remote",l)}return t||(r=r.filter(l=>l.details.type!="col")),r}async defaultPermsForLocalMode(){return(await this.userService.listAccountUsers()).map(t=>({userId:t._id,permission:t.type=="admin"?me.owner:me.editor,user:{_id:t._id,username:t.username,displayedName:t.displayedName,profileImage:t.profileImage},permissionDetails:{direct:!0}}))}async listPermissionsForItem(e,t={}){return t.forceRefresh,await R()?this.defaultPermsForLocalMode():await S("/item/permissions/list",e)}async enrichPermissionsWithUserInfo(e){const t=[];for(const s of e){const n=await this.userService.getUserById(s.userId);t.push({...s,user:n?{_id:n._id,username:n.username,displayedName:n.displayedName,profileImage:n.profileImage}:void 0,permissionDetails:{direct:!0}})}return t}async addItemAttachment(e){return await this.itemAttachmentService.addItemAttachment(e)}async rediscoverQueue(e){return await this.itemDiscoveryService.rediscoverQueue(e)}async cleanupCandidates(e){return await this.itemDiscoveryService.cleanupCandidates(e)}async readLaterFeed(e){return await this.itemDiscoveryService.readLaterFeed(e)}async listPermissionsAndReactions(e){if(await R()){let t=await this.userService.listAccountUsers(),s=[];for(let n of t)s.push({userId:n._id,permission:n.type=="admin"?me.owner:me.editor,user:n});return{permissions:s,reactions:[]}}return S("/item/permissionsAndReactions/list",e)}async listItemReactions(e){return await R()?[]:S("/item/reactions/list",e)}async listComments(e){return await R()?[]:(await S("/comment/list",e)).records}async getItemPathTree(e,t={}){t.forceRefresh;const s=e.userId||await this.userService.getCurrentUserId();return await R()?await this.getItemPathTreeLocal(e.itemId,s):await S("/item/pathtree",e)}async getItemPathTreeLocal(e,t){const s=await this.indexService.getDataIndex(t),n=[],i=6;let a=e;for(let r=0;r<i;r++){const c=await s.itemRelationStore.getParentCollectionIds(a);if(c.length===0)break;const o=await s.itemDataStore.getById(c[0]);if(!o)break;const l=await s.itemRelationStore.getRelationsForItem(c[0]);o.collectionRelations=l.map(f=>({_id:f._id,collectionId:f.collectionId,order:f.order,createdAt:f.createdAt})),o.collectionIds=l.map(f=>f.collectionId);const d=c.slice(1).map(f=>({collectionId:f,_id:`${f}_${a}`})),u=r>=i-1;n.push({item:o.details,others:d,earlyEnd:u}),a=c[0]}return n}async listFilesByRef(e){return await R()?[]:S("/userfile/listFilesByRef",e)}async updateItem(e){var o,l,d,u,f,y,m,w,I,U,F,_;const t=await R();e.data&&(this.normalizeUrlHostnames(e.data),this.applyRequirementNormalization(e.data));let s=!1,n=null;const i=((o=e==null?void 0:e.data)==null?void 0:o.info)&&Object.prototype.hasOwnProperty.call(e.data.info,"value");if((l=e.data)!=null&&l.url||i&&!((d=e.data)!=null&&d.type)){if(n=await this.itemRepo.getItemById(e.itemId),!n&&!t&&navigator.onLine)try{n=await S("/item/infoById",{itemId:e.itemId}),n&&await this.itemRepo.storeItems([n])}catch(C){console.warn(`[ItemService] Failed to hydrate missing local item ${e.itemId} before update`,C)}(u=e.data)!=null&&u.url&&(s=((f=n==null?void 0:n.details)==null?void 0:f.url)!==e.data.url)}let a=null,r=!1;if(i){const C={...(n==null?void 0:n.details)||{},...e.data};if(r=this.isPagedTextItemType(C),r){const A=(m=(y=e.data)==null?void 0:y.info)==null?void 0:m.value,v=A==null?"":typeof A=="string"?A:String(A);a=v&&v.trim().length>0?v:null}}if(a)try{n||(n=await this.itemRepo.getItemById(e.itemId));const C=Ne(n,0),A=C==null?void 0:C.fileId,v=((w=e.data)==null?void 0:w.encInfo)||((I=n==null?void 0:n.details)==null?void 0:I.encInfo);if(A){const T=Date.now(),E=this._latestPageHistoryTimestampMs(n,0),x=E==null?null:T-E;if(x==null||Number.isFinite(x)&&x>
5=5*60*1e3){const z=await this.tryLoadMarkdownFromUserFileId(A);if(z!=null&&z.trim()!==a.trim())try{await this.maybeSavePageHistorySnapshot({itemId:e.itemId,pageIndex:0,encInfo:v,text:z,existingItem:n,nowMs:T})}catch(g){console.warn("[ItemService] Failed to save page0 history snapshot; continuing:",g)}}}await this.savePagedTextAttachment({itemId:e.itemId,encInfo:v,text:a,existingFileId:A,filename:Ke}),e.data.info||(e.data.info={value:""}),e.data.info.value=tt(a),e.data.info.editor||(e.data.info.editor="txt")}catch(C){console.warn("[ItemService] Failed to save page0.md attachment on update; keeping full inline text:",C)}let c=!1;try{await this.itemRepo.updateItemLocal(e.itemId,e.data)}catch(C){const A=C instanceof Error?C.message:String(C),v=/not found/i.test(A);if(t||!navigator.onLine||!v)throw C;c=!0,console.warn(`[ItemService] Local item ${e.itemId} missing during update; falling back to remote sync first.`)}if(!t&&(await S("/item/update",e),c))try{const C=await S("/item/infoById",{itemId:e.itemId});C&&await this.itemRepo.storeItems([C])}catch(C){console.warn(`[ItemService] Failed to rehydrate item ${e.itemId} after remote update`,C)}if(s&&e.data.url){const C=e.data.encInfo||((U=n==null?void 0:n.details)==null?void 0:U.encInfo);h("URL changed, fetching metadata for new URL",e.data.url),this.metaDataService.fetchAndPersistMetadata(e.itemId,e.data.url,C,{skipBanner:!1,updateSubType:!0,currentType:e.data.type??((F=n==null?void 0:n.details)==null?void 0:F.type)??null,currentSubType:e.data.subType??((_=n==null?void 0:n.details)==null?void 0:_.subType)??null}).then(A=>{A.success?(h("Metadata refreshed after URL change",A.subType),this.indexService.updateDataIndex()):console.warn(`Metadata refresh failed after URL change for ${e.itemId}:`,A.error)}).catch(A=>{console.error("Error refreshing metadata after URL change:",A)})}return e.itemId}async getItemRelationshipInfo(e){return await R()?{parents:[],children:[]}:S("/collection/getItemRelInfo",e)}async getItemParents(e){return await R()?[]:S("/item/parents/bychildid",e)}async listSharedWithUser(e){return await R()?[]:S("/item/listSharedWithUser",{userId:e.userId})}async listRecentAccessibleByUser(e){return await R()?[]:S("/item/listRecentAccessibleByUser",{userId:e.userId,limit:e.limit})}async listSharedByUser(e){return await R()?[]:S("/item/listSharedByUser",{userId:e.userId})}async updateItemFeedback(e){if(await R())await this.itemRepo.updateItemFeedbackLocal(e);else return S("/item/feedback/value/update",e)}async listItemsWithFeedback(e){return await R()?[]:S("/item/listWithFeedback",{userId:e.userId,feedbackType:e.feedbackType,limit:e.limit||1e3})}async getHiddenItems(e){return await R()?await(await this.indexService.getDataIndex()).itemDataStore.listWhere(s=>{var n;return((n=s==null?void 0:s.details)==null?void 0:n.hidden)===!0}):S("/library/hidden",{userId:e.userId})}async getUncategorizedItems(e){if(await R()){const t=await this.indexService.getDataIndex(),s=await t.itemRelationStore.getAllCategorizedItemIds();return await t.itemDataStore.listWhere(n=>{var i;return!s.has(n.itemId)&&((i=n==null?void 0:n.details)==null?void 0:i.type)!=="col"})}return S("/library/uncategorized",{userId:e.userId})}async listLibraryRoot(e,t){return await R()?this.listLibraryRootLocal(e):await S("/library/root",e)}async listLibraryRootLocal(e){const t=await this.userService.getCurrentUserId(),s=(e==null?void 0:e.userId)||t,n=await this.indexService.getDataIndex(s),i=await n.itemDataStore.findByType("col"),a=i.map(o=>o.itemId),r=await n.itemRelationStore.getCollectionIdsForItems(a);let c=i.filter(o=>(r.get(o.itemId)||[]).length===0);if(await R()){let o=await this.defaultPermsForLocalMode();const l=o.find(d=>d.userId===t);for(let d of c)d.permissions=o,d.details.permissionUserId=l.userId,d.details.permission=l.permission}return c}async listCollectionsByUser(e){const t=await this.userService.getCurrentUserId();if(((e==null?void 0:e.userId)||await this.userService.getCurrentUserId())===t){const n=(e==null?void 0:e.userId)||await this.userService.getCurrentUserId();return(await(await this.indexService.getDataIndex(n)).itemDataStore.listAll()).filter(c=>{var o;return((o=c.details)==null?void 0:o.type)==="col"})}else return await S("/collection/listByUser",{userId:e.userId})}async getRecentCollections(e){var r;const t=await this.userService.getCurrentUser();if(!((r=t==null?void 0:t.userData)!=null&&r.collectionIdHistory)||t.userData.collectionIdHistory.length===0)return[];const s=t.userData.collectionIdHistory.slice(0,e.limit||12),n=[...new Set(s)],a=(await this.itemRepo.getItemsByIds(n,t._id)).filter(c=>{var o;return((o=c.details)==null?void 0:o.type)==="col"});if(e.preserveOrder){const c=new Map(a.map(o=>[o.itemId,o]));return n.map(o=>c.get(o)).filter(o=>!!o)}return a}
5async queryCollectionItemsLocal(e,t){if(!e)return[];const s=await this.indexService.getDataIndex(),n=await s.itemRelationStore.getItemIdsForCollection(e);if(n.length===0)return[];const i=new Set(n);return await s.itemDataStore.listWhere(r=>{var c,o;return!(!i.has(r.itemId)||t.hideArchived!==!1&&((c=r.details)!=null&&c.archived)||t.typeFilter&&((o=r.details)==null?void 0:o.type)!==t.typeFilter)})}async queryFromIndexLocal(e,t){const s=await this.indexService.getDataIndex();let n=null,i=null;if(e.uncategorized&&(n=await s.itemRelationStore.getAllCategorizedItemIds()),e.inCollections&&e.inCollections.length>0){const c=await Promise.all(e.inCollections.map(o=>s.itemRelationStore.getItemIdsForCollection(o)));i=new Set(c.flat())}const a=c=>{var o,l,d,u,f,y,m,w,I,U,F;if(e.idsRequired&&(!e.ids||e.ids.length===0)||(o=e.ids)!=null&&o.length&&!e.ids.includes(c.itemId)||e.archived!==void 0&&!!((l=c.details)!=null&&l.archived)!==e.archived||e.hidden!==void 0&&((d=c.feedback)==null?void 0:d.isHidden)!==e.hidden||e.uncategorized&&(n!=null&&n.has(c.itemId)||((u=c.details)==null?void 0:u.type)==="col")||e.itemTypes&&e.itemTypes.length>0&&(!((f=c.details)!=null&&f.type)||!e.itemTypes.includes(c.details.type)))return!1;if(e.subTypes&&e.subTypes.length>0){const _=(y=c.details)==null?void 0:y.subType;if(!_||!e.subTypes.includes(_))return!1}if(e.excludeSubTypes&&e.excludeSubTypes.length>0){const _=(m=c.details)==null?void 0:m.subType;if(_&&e.excludeSubTypes.includes(_))return!1}if(e.effectiveTypes&&e.effectiveTypes.length>0&&!e.effectiveTypes.includes(ct(c.details))||e.eduValues&&e.eduValues.length>0&&!e.eduValues.includes(ot((w=c.details)==null?void 0:w.useCriteria)))return!1;if(e.tags&&e.tags.length>0){const _=e.tags.map(A=>A.toLowerCase()),C=(I=c.details)==null?void 0:I.tags;if(!Array.isArray(C)||!C.some(A=>typeof A=="string"&&_.includes(A.toLowerCase())))return!1}if(i&&!i.has(c.itemId))return!1;if(e.publishIds&&e.publishIds.length>0){const _=(U=c.details)==null?void 0:U.publishId;if(!_||!e.publishIds.includes(_))return!1}if(e.urls&&e.urls.length>0){const _=(F=c.details)==null?void 0:F.url;if(!_||!e.urls.includes(_))return!1}return!(e.attributeKey&&e.attributeValue&&c[e.attributeKey]!==e.attributeValue)};return await s.itemDataStore.listWhere(a)}};k(Pe,"_staticInstance",null);let et=Pe;export{Ge as A,Qe as B,ve as C,Re as F,ce as I,_s as L,he as M,Te as a,et as b,qs as c,Je as d,ln as e,dn as f,hs as g,xs as l};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.