s&&!this.pendingRefreshes.has(i.id)&&(this.pendingRefreshes.add(i.id),this.fetchSubscription(i.id).finally(()=>this.pendingRefreshes.delete(i.id)))):this.pendingRefreshes.has(i.id)||(this.pendingRefreshes.add(i.id),this.fetchSubscription(i.id).finally(()=>this.pendingRefreshes.delete(i.id)))}),t}getEventsForSubscription(t){let n=this.cache.get(t);if(!n){let l=this.subscriptions.find(c=>c.id===t);return l&&l.enabled&&!this.pendingRefreshes.has(t)&&(this.pendingRefreshes.add(t),this.fetchSubscription(t).finally(()=>this.pendingRefreshes.delete(t))),[]}let i=new Date,a=new Date(n.expires),s=new Date(a.getTime()+this.CACHE_GRACE_PERIOD);return i>=s?(this.pendingRefreshes.has(t)||(this.pendingRefreshes.add(t),this.fetchSubscription(t).finally(()=>this.pendingRefreshes.delete(t))),[]):(i>a&&!this.pendingRefreshes.has(t)&&(this.pendingRefreshes.add(t),this.fetchSubscription(t).finally(()=>this.pendingRefreshes.delete(t))),[...n.events])}async refreshAllSubscriptions(){let t=this.subscriptions.filter(n=>n.enabled);for(let n of t)await this.fetchSubscription(n.id)}getVaultBasePath(){let t=this.plugin.app.vault.adapter;if(typeof(t==null?void 0:t.getBasePath)=="function")try{let n=t.getBasePath();return typeof n=="string"&&n.trim()?n:void 0}catch(n){PD.warn("Failed to resolve vault base path for local ICS file:",{category:"provider",operation:"resolve-vault-base-path-local-ics-file",error:n});return}}normalizePathSeparators(t){return t.trim().replace(/\\/g,"/").replace(/^\.\/+/u,"")}isAbsoluteFilePath(t){return t.startsWith("/")||/^[A-Za-z]:\//u.test(t)}normalizeLocalICSFilePath(t){let n=this.normalizePathSeparators(t);if(!this.isAbsoluteFilePath(n))return n;let i=this.getVaultBasePath();if(i){let a=this.normalizePathSeparators(i).replace(/\/+$/u,"");if(n.startsWith(`${a}/`))return n.slice(a.length+1)}throw new Error('Local ICS files must be inside the current Obsidian vault. Move the file into the vault or use a vault-relative path such as "Calendar.ics".')}normalizeLocalICSFilePathIfPossible(t){try{return this.normalizeLocalICSFilePath(t)}catch(n){return this.normalizePathSeparators(t)}}async readLocalICSFile(t){try{let n=this.normalizeLocalICSFilePath(t),i=this.plugin.app.vault.getAbstractFileByPath(n);if(!i||!(i instanceof JO.TFile))throw new Error(`File not found: ${n}`);if(i.extension!=="ics")throw new Error(`File is not an ICS file: ${n}`);return await this.plugin.app.vault.cachedRead(i)}catch(n){throw new Error(`Failed to read local ICS file "${t}": ${n instanceof Error?n.message:String(n)}`)}}startFileWatcher(t){if(!t.filePath)return;this.stopFileWatcher(t.id);let n=this.normalizeLocalICSFilePathIfPossible(t.filePath),i=(l,c)=>{(l.path===n||c===n)&&window.setTimeout(()=>{this.fetchSubscription(t.id)},1e3)},a=this.plugin.app.vault.on("modify",i),s=this.plugin.app.vault.on("rename",i),o=this.plugin.app.vault.on("delete",l=>{l.path===n&&this.lastError.set(t.id,"Local ICS file was deleted")});this.fileWatchers.set(t.id,()=>{this.plugin.app.vault.offref(a),this.plugin.app.vault.offref(s),this.plugin.app.vault.offref(o)}),this.startFileRefreshTimer(t)}stopFileWatcher(t){let n=this.fileWatchers.get(t);n&&(n(),this.fileWatchers.delete(t))}async refreshSubscription(t){await this.fetchSubscription(t)}startRefreshTimer(t){this.stopRefreshTimer(t.id),this.startRemoteRefreshTimer(t)}startFileRefreshTimer(t){let n=t.refreshInterval*60*1e3,i=window.setTimeout(()=>{this.refreshTimers.delete(t.id),this.fetchSubscription(t.id).finally(()=>{this.shouldContinueRefresh(t.id)&&this.startFileRefreshTimer(t)})},n);this.refreshTimers.set(t.id,i)}startRemoteRefreshTimer(t){let n=t.refreshInterval*60*1e3,i=window.setTimeout(()=>{this.refreshTimers.delete(t.id),this.fetchSubscription(t.id).finally(()=>{this.shouldContinueRefresh(t.id)&&this.startRemoteRefreshTimer(t)})},n);this.refreshTimers.set(t.id,i)}shouldContinueRefresh(t){return!this.destroyed&&this.subscriptions.some(n=>n.id===t&&n.enabled)}stopRefreshTimer(t){let n=this.refreshTimers.get(t);n&&(window.clearTimeout(n),this.refreshTimers.delete(t))}generateId(){return"ics_"+Math.random().toString(36).substring(2,11)+Date.now().toString(36)}destroy(){this.destroyed=!0,this.refreshTimers.forEach(t=>window.clearTimeout(t)),this.refreshTimers.clear(),this.fileWatchers.forEach(t=>t()),this.fileWatchers.clear(),this.cache.clear(),this.pendingRefreshes.clear(),this.removeAllListeners()}getLocalICSFiles(){return this.plugin.app.vault.getFiles().filter(t=>t.extension==="ics").sort((t,n)=>t.path.localeCompare(n.path))}}});var MD,ld,XO,H0e=y(()=>{MD=require("obsidian");Br();Kq();Ne();Eb();Ct();JN();G();ls();ld=I({tag:"Services/ICSNoteService"}),XO=class{constructor(e){this.plugin=e}translate(e,t){return this.plugin.i18n.translate(e,t)}findEventById(e){var s,o,l,c,d,u,p,m,f;let t=e.trim();if(!t)return null;let n=(s=this.plugin.icsSubscriptionService)==null?void 0:s.getAllEvents().find(h=>h.id===t);if(n){let h=(l=(o=this.plugin.icsSubscriptionService)==null?void 0:o.getSubscriptions().find(g=>g.id===n.subscriptionId))==null?void 0:l.name;return{event:n,subscriptionName:h}}let i=(c=this.plugin.googleCalendarService)==null?void 0:c.getAllEvents().find(h=>h.id===t);if(i){let h=i.subscriptionId.replace("google-",""),g=((u=(d=this.plugin.googleCalendarService)==null?void 0:d.getAvailableCalendars().find(v=>v.id===h))==null?void 0:u.summary)||"Google Calendar";return{event:i,subscriptionName:g}}let a=(p=this.plugin.microsoftCalendarService)==null?void 0:p.getAllEvents().find(h=>h.id===t);if(a){let h=a.subscriptionId.replace("microsoft-",""),g=((f=(m=this.plugin.microsoftCalendarService)==null?void 0:m.getAvailableCalendars().find(v=>v.id===h))==null?void 0:f.summary)||"Microsoft Calendar";return{event:a,subscriptionName:g}}return null}getLoadedCalendarEvents(){var e,t,n,i,a,s;return[...(t=(e=this.plugin.icsSubscriptionService)==null?void 0:e.getAllEvents())!=null?t:[],...(i=(n=this.plugin.googleCalendarService)==null?void 0:n.getAllEvents())!=null?i:[],...(s=(a=this.plugin.microsoftCalendarService)==null?void 0:a.getAllEvents())!=null?s:[]]}getExplicitSeriesId(e){var n;return((n=e.recurringEventId)==null?void 0:n.trim())||null}buildEventSeriesIndex(){let e=new Map;for(let i of this.getLoadedCalendarEvents()){let a=this.getExplicitSeriesId(i);if(!a)continue;let s=e.get(a);s||(s=new Set,e.set(a,s)),s.add(i.id)}let t=new Map,n=new Map;for(let[i,a]of e){n.set(i,a);for(let s of a)t.set(s,i)}return{seriesIdByEventId:t,eventIdsBySeriesId:n}}getRelatedEventIds(e,t){var s;let n=new Set([e]),i=t.seriesIdByEventId.get(e),a=t.eventIdsBySeriesId.has(e)?e:i;if(a){n.add(a);for(let o of(s=t.eventIdsBySeriesId.get(a))!=null?s:[])n.add(o)}return n}eventIdsMatchSeries(e,t,n){for(let i of this.getRelatedEventIds(e,n))if(t.has(i))return!0;return!1}async getRelatedNoteCountsByEventId(){let e=new Map,t=this.plugin.fieldMapper.toUserField("icsEventId"),n=this.buildEventSeriesIndex(),i=(a,s)=>{for(let o of this.normalizeEventIds(a))for(let l of this.getRelatedEventIds(o,n)){let c=e.get(l);c||(c=new Set,e.set(l,c)),c.add(s)}};try{let a=await this.plugin.cacheManager.getAllTasks();for(let o of a)i(o.icsEventId,o.path);let s=this.plugin.app.vault.getMarkdownFiles();for(let o of s){let l=this.plugin.app.metadataCache.getFileCache(o),c=l==null?void 0:l.frontmatter;c&&i(c[t],o.path)}}catch(a){return ld.error("Error counting related notes for ICS events:",{category:"provider",operation:"counting-related-notes-ics-events",error:a}),new Map}return new Map(Array.from(e.entries()).map(([a,s])=>[a,s.size]))}normalizeEventIds(e){return(Array.isArray(e)?e:e?[e]:[]).filter(n=>typeof n=="string").map(n=>n.trim()).filter(Boolean)}async createTaskFromICS(e,t){var n;try{let i=this.plugin.icsSubscriptionService.getSubscriptions().find(l=>l.id===e.subscriptionId),a=(i==null?void 0:i.name)||"Unknown Calendar",s=(t==null?void 0:t.scheduled)!==void 0?t.scheduled:this.computeScheduledFromICSEvent(e),o={title:(t==null?void 0:t.title)||e.title,status:(t==null?void 0:t.status)||this.plugin.settings.defaultTaskStatus,priority:(t==null?void 0:t.priority)||this.plugin.settings.defaultTaskPriority,due:(t==null?void 0:t.due)!==void 0?t.due:(n=this.plugin.settings.icsIntegration)!=null&&n.useICSEndAsDue?this.computeDueFromICSEnd(e):void 0,scheduled:s,contexts:(t==null?void 0:t.contexts)||(e.location?[e.location]:void 0),projects:t==null?void 0:t.projects,tags:(t==null?void 0:t.tags)||[this.plugin.fieldMapper.toUserField("icsEventTag")],timeEstimate:(t==null?void 0:t.timeEstimate)||this.calculateEventDuration(e),details:(t==null?void 0:t.details)||this.buildICSEventDetails(e,a),icsEventId:[e.id],creationContext:"ics-event",dateCreated:Ye(),dateModified:Ye(),...Object.fromEntries(Object.entries(t||{}).filter(([l])=>l!=="due"))};return await this.plugin.taskService.createTask(o,{applyDefaults:!1})}catch(i){let a=i instanceof Error?i.message:String(i);throw ld.error("Error creating task from ICS event:",{category:"provider",operation:"creating-task-ics-event",details:{icsEventId:e.id,icsEventTitle:e.title},error:a}),new Error(`Failed to create task from ICS event: ${a}`)}}computeScheduledFromICSEvent(e){try{if(!e.start)return;let t=e.allDay&&/^\d{4}-\d{2}-\d{2}$/.test(e.start)?e.start+"T00:00:00":e.start,n=new Date(t);return e.allDay?ce(n):P(n,"yyyy-MM-dd'T'HH:mm")}catch(t){return ld.warn("Failed to compute scheduled from ICS event start:",{category:"provider",operation:"compute-scheduled-ics-event-start",details:{start:e.start},error:t}),e.start}}computeDueFromICSEnd(e){try{if(!e.end)return;if(e.allDay){if(!e.start)return;let i=/^\d{4}-\d{2}-\d{2}$/.test(e.start)?e.start+"T00:00:00":e.start,a=new Date(i);return ce(a)}let t=/^\d{4}-\d{2}-\d{2}$/.test(e.end)?e.end+"T00:00:00":e.end,n=new Date(t);return P(n,"yyyy-MM-dd'T'HH:mm")}catch(t){ld.warn("Failed to compute due from ICS event end:",{category:"provider",operation:"compute-due-ics-event-end",details:{end:e.end},error:t});return}}async createNoteFromICS(e,t){var n;try{let i=this.plugin.icsSubscriptionService.getSubscriptions().find(O=>O.id===e.subscriptionId),a=(i==null?void 0:i.name)||"Unknown Calendar",s=e.allDay&&/^\d{4}-\d{2}-\d{2}$/.test(e.start)?e.start+"T00:00:00":e.start,o=new Date(s),l=(t==null?void 0:t.title)||`${e.title} - ${P(o,"PPP")}`,c=(t==null?void 0:t.folder)||((n=this.plugin.settings.icsIntegration)==null?void 0:n.defaultNoteFolder)||"",d=eR(c,{date:o,icsData:{title:e.title,location:e.location,description:e.description}}),u={title:e.title,priority:"",status:"",date:o,dueDate:e.end,scheduledDate:e.start,icsEventTitle:e.title,icsEventLocation:e.location,icsEventDescription:e.description},p=Xke(u,this.plugin.settings),m=await Sb(p,d,this.plugin.app.vault),f=d?`${d}/${m}.md`:`${m}.md`;d&&await Ap(this.plugin.app.vault,d);let h={title:l,priority:"",status:"",contexts:e.location?[e.location]:[],tags:[this.plugin.fieldMapper.toUserField("icsEventTag")],timeEstimate:0,dueDate:e.end||"",scheduledDate:e.start||"",details:e.description||"",parentNote:"",icsEventTitle:e.title,icsEventStart:e.start,icsEventEnd:e.end||"",icsEventLocation:e.location||"",icsEventDescription:e.description||"",icsEventUrl:e.url||"",icsEventSubscription:a,icsEventId:e.id},g=this.plugin.fieldMapper.toUserField("dateCreated"),v=this.plugin.fieldMapper.toUserField("dateModified"),k={title:l,[g]:Ye(),[v]:Ye(),tags:[this.plugin.fieldMapper.toUserField("icsEventTag")],[this.plugin.fieldMapper.toUserField("icsEventId")]:[e.id]},b=this.buildICSEventDetails(e,a);if(t!=null&&t.template)try{let O=(0,MD.normalizePath)(t.template.trim()),L=this.plugin.app.vault.getAbstractFileByPath(O.endsWith(".md")?O:`${O}.md`);if(L instanceof MD.TFile){let N=await this.plugin.app.vault.read(L),R=QN(N,h);k={...k,...R.frontmatter},b=R.body||b}else ld.warn(`ICS note template not found: ${O}`,{category:"provider",operation:"ics-note-template-not-found"}),Ee(this.plugin.emitter,this.translate("services.icsNote.notices.templateNotFound",{path:O}))}catch(O){ld.error("Error processing ICS note template:",{category:"provider",operation:"processing-ics-note-template",error:O}),Ee(this.plugin.emitter,this.translate("services.icsNote.notices.templateProcessError",{template:t.template}))}let S=`${Object.keys(k).length>0?`---
+${Object.entries(k).map(([O,L])=>`${O}: ${this.formatYamlValue(L)}`).join(`
+`)}
+---
+
+`:""}${b}`,x=await this.plugin.app.vault.create(f,S),C=Array.isArray(k.tags)?k.tags.filter(O=>typeof O=="string"):[],D=typeof k[g]=="string"?k[g]:void 0,_={title:l,path:x.path,tags:C,createdDate:D,lastModified:Date.now()};return{file:x,noteInfo:_}}catch(i){let a=i instanceof Error?i.message:String(i);throw ld.error("Error creating note from ICS event:",{category:"provider",operation:"creating-note-ics-event",details:{icsEventId:e.id,icsEventTitle:e.title},error:a}),new Error(`Failed to create note from ICS event: ${a}`)}}async findRelatedNotes(e){try{let t=[],n=new Set,i=this.plugin.fieldMapper.toUserField("icsEventId"),a=this.buildEventSeriesIndex(),s=this.getRelatedEventIds(e.id,a),o=d=>this.normalizeEventIds(d).some(u=>this.eventIdsMatchSeries(u,s,a)),l=await this.plugin.cacheManager.getAllTasks();for(let d of l)if(o(d.icsEventId)){if(n.has(d.path))continue;t.push(d),n.add(d.path)}let c=this.plugin.app.vault.getMarkdownFiles();for(let d of c)try{let u=this.plugin.app.metadataCache.getFileCache(d),p=u==null?void 0:u.frontmatter;if(p&&o(p[i])){if(n.has(d.path))continue;let m={title:p.title||d.basename,path:d.path,tags:p.tags||[],createdDate:p.dateCreated,lastModified:d.stat.mtime};t.push(m),n.add(d.path)}}catch(u){continue}return t}catch(t){return ld.error("Error finding related notes for ICS event:",{category:"provider",operation:"finding-related-notes-ics-event",error:t}),[]}}async linkNoteToICS(e,t){try{let n=this.plugin.app.vault.getAbstractFileByPath(e);if(!(n instanceof MD.TFile))throw new Error(`Cannot find note file: ${e}`);await this.plugin.app.fileManager.processFrontMatter(n,i=>{let a=this.plugin.fieldMapper.toUserField("icsEventId"),s=i[a];s?Array.isArray(s)||(s=[s]):s=[],s.includes(t.id)||s.push(t.id),i[a]=s;let o=this.plugin.fieldMapper.toUserField("dateModified");i[o]=Ye()}),Ee(this.plugin.emitter,this.translate("services.icsNote.notices.linkedToEvent",{title:t.title}))}catch(n){let i=n instanceof Error?n.message:String(n);throw ld.error("Error linking note to ICS event:",{category:"provider",operation:"linking-note-ics-event",details:{notePath:e,icsEventId:t.id},error:i}),new Error(`Failed to link note to ICS event: ${i}`)}}buildICSEventDetails(e,t){let n=[];if(n.push(`# ${e.title}`),n.push(""),e.start){let i=e.allDay&&/^\d{4}-\d{2}-\d{2}$/.test(e.start)?e.start+"T00:00:00":e.start,a=new Date(i);n.push(`**Start:** ${P(a,"PPPp")}`)}if(e.end&&!e.allDay){let i=/^\d{4}-\d{2}-\d{2}$/.test(e.end)?e.end+"T00:00:00":e.end,a=new Date(i);n.push(`**End:** ${P(a,"PPPp")}`)}return e.location&&n.push(`**Location:** ${e.location}`),n.push(`**Calendar:** ${t}`),e.description&&(n.push(""),n.push("## Description"),n.push(e.description)),e.url&&(n.push(""),n.push(`**Event URL:** ${e.url}`)),n.join(`
+`)}formatYamlValue(e){return typeof e=="string"?e.includes(":")||e.includes("#")||e.includes("[")||e.includes("{")?`"${e.replace(/"/g,'\\"')}"`:e:Array.isArray(e)?`[${e.map(t=>typeof t=="string"?`"${t}"`:t).join(", ")}]`:String(e)}calculateEventDuration(e){if(!(!e.start||!e.end))try{let t=e.allDay&&/^\d{4}-\d{2}-\d{2}$/.test(e.start)?e.start+"T00:00:00":e.start,n=e.allDay&&/^\d{4}-\d{2}-\d{2}$/.test(e.end)?e.end+"T00:00:00":e.end,i=new Date(t).getTime(),a=new Date(n).getTime();if(isNaN(i)||isNaN(a))return;let s=a-i,o=Math.round(s/(1e3*60));return o>0&&o<1440?o:void 0}catch(t){ld.warn("Error calculating event duration:",{category:"provider",operation:"calculating-event-duration",error:t});return}}}});var eL,ql,LT,EOr,FT=y(()=>{eL={TOKEN_REFRESH_BUFFER_MS:3e5,CALLBACK_PORT_START:8080,CALLBACK_PORT_END:8090},ql={REFRESH_INTERVAL_MS:900*1e3,MIN_MANUAL_REFRESH_INTERVAL_MS:30*1e3,MAX_RESULTS_PER_REQUEST:2500,VIEW_RANGE:{DAYS_BEFORE:30,DAYS_AFTER:90},DEFAULT_EVENT_DURATION_MS:3600*1e3,MAX_REMINDER_MINUTES:40320,RATE_LIMIT:{MAX_RETRIES:3,INITIAL_BACKOFF_MS:1e3,MAX_BACKOFF_MS:16e3,BACKOFF_MULTIPLIER:2}},LT={REFRESH_INTERVAL_MS:900*1e3,MIN_MANUAL_REFRESH_INTERVAL_MS:30*1e3,MAX_RESULTS_PER_REQUEST:50,VIEW_RANGE:{DAYS_BEFORE:30,DAYS_AFTER:90},DEFAULT_EVENT_DURATION_MS:3600*1e3,RATE_LIMIT:{MAX_RETRIES:3,INITIAL_BACKOFF_MS:1e3,MAX_BACKOFF_MS:16e3,BACKOFF_MULTIPLIER:2}},EOr={SECOND_MS:1e3,MINUTE_MS:60*1e3,HOUR_MS:3600*1e3,DAY_MS:1440*60*1e3}});var _D,AD,ys,Pg,ID,Bi,jm,$T,Yo,Mg,zT=y(()=>{_D=class extends Error{constructor(t,n){super(t);this.code=n;this.name="TaskNotesServiceError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},AD=class extends _D{constructor(t,n,i){super(t,i);this.provider=n;this.name="OAuthError"}},ys=class extends AD{constructor(e){super(`${e} authentication expired. Please reconnect.`,e,"TOKEN_EXPIRED"),this.name="TokenExpiredError"}},Pg=class extends AD{constructor(t,n,i){let a=`${t} connection expired. Please reconnect in Settings > Integrations.`;super(a,t,"TOKEN_REFRESH_FAILED");this.oauthErrorCode=n;this.oauthErrorDescription=i;this.name="TokenRefreshError"}},ID=class extends AD{constructor(e){super(`${e} OAuth is not configured. Please provide OAuth credentials in settings.`,e,"NOT_CONFIGURED"),this.name="OAuthNotConfiguredError"}},Bi=class extends _D{constructor(t,n,i){super(t,i);this.statusCode=n;this.name="GoogleCalendarError"}},jm=class extends Bi{constructor(e){super(`Calendar event not found: ${e}`,404,"EVENT_NOT_FOUND"),this.name="EventNotFoundError"}},$T=class extends Bi{constructor(e){super(`Calendar not found: ${e}`,404,"CALENDAR_NOT_FOUND"),this.name="CalendarNotFoundError"}},Yo=class extends Bi{constructor(e){let t=e?`Rate limit exceeded. Retry after ${e} seconds.`:"Rate limit exceeded. Please try again later.";super(t,429,"RATE_LIMIT"),this.name="RateLimitError"}},Mg=class extends _D{constructor(t,n){super(t,"VALIDATION_ERROR");this.field=n;this.name="ValidationError"}}});function V0e(){if(!_g.Platform.isDesktopApp)throw new Error("OAuth redirect handling is only available on desktop.");return M3||(M3=require("http")),M3}var _g,Wl,M3,tL,q0e=y(()=>{_g=require("obsidian");FT();zT();G();ls();Wl=I({tag:"Services/OAuthService"}),M3=null;tL=class{constructor(e){this.callbackServer=null;this.pendingOAuthState=new Map;this.tokenRefreshPromises=new Map;this.configs={google:{provider:"google",clientId:"",redirectUri:"http://127.0.0.1:8080",scope:["https://www.googleapis.com/auth/calendar.readonly","https://www.googleapis.com/auth/calendar.events"],authorizationEndpoint:"https://accounts.google.com/o/oauth2/v2/auth",tokenEndpoint:"https://oauth2.googleapis.com/token",deviceCodeEndpoint:"https://oauth2.googleapis.com/device/code",revocationEndpoint:"https://oauth2.googleapis.com/revoke"},microsoft:{provider:"microsoft",clientId:"",redirectUri:"http://localhost:8080",scope:["Calendars.Read","Calendars.ReadWrite","offline_access"],authorizationEndpoint:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenEndpoint:"https://login.microsoftonline.com/common/oauth2/v2.0/token",deviceCodeEndpoint:"https://login.microsoftonline.com/common/oauth2/v2.0/devicecode",revocationEndpoint:"https://login.microsoftonline.com/common/oauth2/v2.0/logout"}};this.plugin=e,this.loadClientIds()}async loadClientIds(){this.configs.google.clientId=this.plugin.settings.googleOAuthClientId||"",this.configs.google.clientSecret=this.plugin.settings.googleOAuthClientSecret||"",this.configs.microsoft.clientId=this.plugin.settings.microsoftOAuthClientId||"",this.configs.microsoft.clientSecret=this.plugin.settings.microsoftOAuthClientSecret||""}async authenticate(e){if(!this.configs[e].clientId)throw new ID(e);if(!(e==="google"&&this.plugin.settings.googleOAuthClientId||e==="microsoft"&&this.plugin.settings.microsoftOAuthClientId))throw new ID(e);return await this.authenticateStandard(e)}async authenticateStandard(e){try{let t=this.configs[e];if(!_g.Platform.isDesktopApp)throw Ee(this.plugin.emitter,"OAUTH authentication requires the desktop app."),new Error("OAuth authentication requires the desktop app.");let n=this.generateCodeVerifier(),i=await this.generateCodeChallenge(n),a=this.generateState(),s=await this.findAvailablePort(eL.CALLBACK_PORT_START,eL.CALLBACK_PORT_END);await this.startCallbackServer(s);let o=t.redirectUri;t.redirectUri=`http://127.0.0.1:${s}`;try{let l=this.buildAuthorizationUrl(t,i,a);this.pendingOAuthState.set(a,{provider:e,codeVerifier:n,resolve:()=>{},reject:()=>{}}),Ee(this.plugin.emitter,`Opening browser for ${e} authorization...`),window.open(l,"_blank");let c=await this.waitForCallback(a,3e5),d=await this.exchangeCodeForTokens(t,c,n);await this.storeConnection(e,d),Ee(this.plugin.emitter,`Successfully connected to ${e} Calendar!`)}finally{t.redirectUri=o}}catch(t){throw Wl.error(`OAuth authentication failed for ${e}:`,{category:"provider",operation:"oauth-authentication",error:t}),Ee(this.plugin.emitter,`Failed to connect to ${e}: ${t.message}`),t}finally{await this.stopCallbackServer()}}async findAvailablePort(e,t){let n=V0e();for(let i=e;i<=t;i++)try{return await new Promise((a,s)=>{let o=n.createServer();o.once("error",s),o.once("listening",()=>{o.close(),a()}),o.listen(i,"127.0.0.1")}),i}catch(a){continue}throw new Error(`No available ports found between ${e} and ${t}`)}generateCodeVerifier(){return this.base64UrlEncode(crypto.getRandomValues(new Uint8Array(32)))}async generateCodeChallenge(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-256",t);return this.base64UrlEncode(new Uint8Array(n))}generateState(){return Array.from(crypto.getRandomValues(new Uint8Array(16))).map(e=>e.toString(16).padStart(2,"0")).join("")}base64UrlEncode(e){let t="";return e.forEach(n=>{t+=String.fromCharCode(n)}),btoa(t).replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}buildAuthorizationUrl(e,t,n){let i=new URLSearchParams({client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:e.scope.join(" "),state:n,code_challenge:t,code_challenge_method:"S256"});return e.provider==="google"&&(i.set("access_type","offline"),i.set("prompt","consent")),`${e.authorizationEndpoint}?${i.toString()}`}async startCallbackServer(e){return new Promise((t,n)=>{if(this.callbackServer){t();return}let i;try{i=V0e()}catch(a){n(a instanceof Error?a:new Error(String(a)));return}this.callbackServer=i.createServer((a,s)=>{this.handleCallback(a,s)}),this.callbackServer.once("error",a=>{Wl.error("OAuth callback server error:",{category:"provider",operation:"oauth-callback-server",error:a}),n(a)}),this.callbackServer.listen(e,"127.0.0.1",()=>{t()})})}async stopCallbackServer(){return new Promise(e=>{if(!this.callbackServer){e();return}this.callbackServer.close(()=>{this.callbackServer=null,e()})})}handleCallback(e,t){let n=e.headers.host,i=Array.isArray(n)?n[0]:n!=null?n:"localhost",a=new URL(e.url||"",`http://${i}`),s=a.searchParams.get("code"),o=a.searchParams.get("state"),l=a.searchParams.get("error");if(t.writeHead(200,{"Content-Type":"text/html"}),l){t.end(`
+
+
+ OAuth Error
+
+ Authorization Failed
+ Error: ${l}
+ You can close this window.
+
+
+ `);let d=o?this.pendingOAuthState.get(o):null;d&&o&&(d.reject(new Error(`OAuth error: ${l}`)),this.pendingOAuthState.delete(o));return}if(!s||!o){t.end(`
+
+
+ OAuth Error
+
+ Invalid Callback
+ Missing required parameters.
+ You can close this window.
+
+
+ `);return}t.end(`
+
+
+ OAuth Success
+
+ Authorization Successful!
+ You can close this window and return to Obsidian.
+