diff --git a/main.js b/main.js index 242a4e9..bdbdbfa 100644 --- a/main.js +++ b/main.js @@ -3,13 +3,13 @@ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ -"use strict";var Mt=Object.create;var B=Object.defineProperty;var Ut=Object.getOwnPropertyDescriptor;var Rt=Object.getOwnPropertyNames;var Ct=Object.getPrototypeOf,Nt=Object.prototype.hasOwnProperty;var Bt=(g,t)=>{for(var e in t)B(g,e,{get:t[e],enumerable:!0})},St=(g,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Rt(t))!Nt.call(g,i)&&i!==e&&B(g,i,{get:()=>t[i],enumerable:!(n=Ut(t,i))||n.enumerable});return g};var Ft=(g,t,e)=>(e=g!=null?Mt(Ct(g)):{},St(t||!g||!g.__esModule?B(e,"default",{value:g,enumerable:!0}):e,g)),$t=g=>St(B({},"__esModule",{value:!0}),g);var Ot={};Bt(Ot,{default:()=>I});module.exports=$t(Ot);var y=require("obsidian");var vt={micropubEndpoint:"",mediaEndpoint:"",accessToken:"",defaultSyndicateTo:[],autoDiscover:!1,siteUrl:"",authorizationEndpoint:"",tokenEndpoint:"",me:"",writeUrlToFrontmatter:!0,mapGardenTags:!0,defaultVisibility:"public",showSyndicationDialog:"when-needed"};var m=require("obsidian");var T=require("obsidian"),w=class{constructor(t,e,n){this.getEndpoint=t;this.getMediaEndpoint=e;this.getToken=n}async fetchConfig(){let t=`${this.getEndpoint()}?q=config`;return(await(0,T.requestUrl)({url:t,method:"GET",headers:this.authHeaders()})).json}async discoverEndpoints(t){let n=(await(0,T.requestUrl)({url:t,method:"GET"})).text,i=this.extractLinkRel(n,"micropub"),s=this.extractLinkRel(n,"token_endpoint"),r;if(i)try{r=(await this.fetchConfigFrom(i))["media-endpoint"]}catch(a){}return{micropubEndpoint:i,tokenEndpoint:s,mediaEndpoint:r}}async createPost(t){var n,i,s;let e={type:["h-entry"],properties:t};try{let r=await(0,T.requestUrl)({url:this.getEndpoint(),method:"POST",headers:{...this.authHeaders(),"Content-Type":"application/json"},body:JSON.stringify(e),throw:!1});if(r.status===201||r.status===202)return{success:!0,url:((n=r.headers)==null?void 0:n.location)||((i=r.headers)==null?void 0:i.Location)||((s=r.json)==null?void 0:s.url)};let a=this.extractError(r.text);return{success:!1,error:`HTTP ${r.status}: ${a}`}}catch(r){return{success:!1,error:String(r)}}}async updatePost(t,e){let n={action:"update",url:t,replace:e};try{let i=await(0,T.requestUrl)({url:this.getEndpoint(),method:"POST",headers:{...this.authHeaders(),"Content-Type":"application/json"},body:JSON.stringify(n),throw:!1});return i.status>=200&&i.status<300?{success:!0,url:t}:{success:!1,error:`HTTP ${i.status}: ${this.extractError(i.text)}`}}catch(i){return{success:!1,error:String(i)}}}async uploadMedia(t,e,n){var h,b,E;let i=this.getMediaEndpoint()||`${this.getEndpoint()}/media`,s=`----MicropubBoundary${Date.now()}`,r=`--${s}\r +"use strict";var Ut=Object.create;var $=Object.defineProperty;var Rt=Object.getOwnPropertyDescriptor;var Ct=Object.getOwnPropertyNames;var Nt=Object.getPrototypeOf,$t=Object.prototype.hasOwnProperty;var Bt=(g,t)=>{for(var e in t)$(g,e,{get:t[e],enumerable:!0})},vt=(g,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Ct(t))!$t.call(g,i)&&i!==e&&$(g,i,{get:()=>t[i],enumerable:!(n=Rt(t,i))||n.enumerable});return g};var Ft=(g,t,e)=>(e=g!=null?Ut(Nt(g)):{},vt(t||!g||!g.__esModule?$(e,"default",{value:g,enumerable:!0}):e,g)),zt=g=>vt($({},"__esModule",{value:!0}),g);var It={};Bt(It,{default:()=>I});module.exports=zt(It);var y=require("obsidian");var kt={micropubEndpoint:"",mediaEndpoint:"",accessToken:"",defaultSyndicateTo:[],autoDiscover:!1,siteUrl:"",authorizationEndpoint:"",tokenEndpoint:"",me:"",writeUrlToFrontmatter:!0,mapGardenTags:!0,defaultVisibility:"public",showSyndicationDialog:"when-needed"};var f=require("obsidian");var T=require("obsidian"),w=class{constructor(t,e,n){this.getEndpoint=t;this.getMediaEndpoint=e;this.getToken=n}async fetchConfig(){let t=`${this.getEndpoint()}?q=config`;return(await(0,T.requestUrl)({url:t,method:"GET",headers:this.authHeaders()})).json}async discoverEndpoints(t){let n=(await(0,T.requestUrl)({url:t,method:"GET"})).text,i=this.extractLinkRel(n,"micropub"),s=this.extractLinkRel(n,"token_endpoint"),r;if(i)try{r=(await this.fetchConfigFrom(i))["media-endpoint"]}catch(a){}return{micropubEndpoint:i,tokenEndpoint:s,mediaEndpoint:r}}async createPost(t){var n,i,s;let e={type:["h-entry"],properties:t};try{let r=await(0,T.requestUrl)({url:this.getEndpoint(),method:"POST",headers:{...this.authHeaders(),"Content-Type":"application/json"},body:JSON.stringify(e),throw:!1});if(r.status===201||r.status===202)return{success:!0,url:((n=r.headers)==null?void 0:n.location)||((i=r.headers)==null?void 0:i.Location)||((s=r.json)==null?void 0:s.url)};let a=this.extractError(r.text);return{success:!1,error:`HTTP ${r.status}: ${a}`}}catch(r){return{success:!1,error:String(r)}}}async updatePost(t,e){let n={action:"update",url:t,replace:e};try{let i=await(0,T.requestUrl)({url:this.getEndpoint(),method:"POST",headers:{...this.authHeaders(),"Content-Type":"application/json"},body:JSON.stringify(n),throw:!1});return i.status>=200&&i.status<300?{success:!0,url:t}:{success:!1,error:`HTTP ${i.status}: ${this.extractError(i.text)}`}}catch(i){return{success:!1,error:String(i)}}}async uploadMedia(t,e,n){var h,b,E;let i=this.getMediaEndpoint()||`${this.getEndpoint()}/media`,s=`----MicropubBoundary${Date.now()}`,r=`--${s}\r Content-Disposition: form-data; name="file"; filename="${e}"\r Content-Type: ${n}\r \r `,a=`\r --${s}--\r -`,l=new TextEncoder().encode(r),c=new TextEncoder().encode(a),d=new Uint8Array(t),p=new Uint8Array(l.length+d.length+c.length);p.set(l,0),p.set(d,l.length),p.set(c,l.length+d.length);let u=await(0,T.requestUrl)({url:i,method:"POST",headers:{...this.authHeaders(),"Content-Type":`multipart/form-data; boundary=${s}`},body:p.buffer,throw:!1});if(u.status===201||u.status===202){let S=((h=u.headers)==null?void 0:h.location)||((b=u.headers)==null?void 0:b.Location)||((E=u.json)==null?void 0:E.url);if(S)return S}throw new Error(`Media upload failed (HTTP ${u.status}): ${this.extractError(u.text)}`)}authHeaders(){return{Authorization:`Bearer ${this.getToken()}`}}extractLinkRel(t,e){var s;let n=new RegExp(`]+rel=["']${e}["'][^>]+href=["']([^"']+)["']|]+href=["']([^"']+)["'][^>]+rel=["']${e}["']`,"i"),i=t.match(n);return(s=i==null?void 0:i[1])!=null?s:i==null?void 0:i[2]}async fetchConfigFrom(t){return(await(0,T.requestUrl)({url:`${t}?q=config`,method:"GET",headers:this.authHeaders()})).json}extractError(t){var e,n;try{let i=JSON.parse(t);return(n=(e=i.error_description)!=null?e:i.error)!=null?n:t.slice(0,200)}catch(i){return t.slice(0,200)}}};var M=Ft(require("crypto")),G=require("obsidian");var kt={cmdPublish:"Publish to Micropub",cmdUpdate:"Update existing Micropub post",noticeOpenNote:"Open a Markdown note to publish.",noticeNoEndpoint:"\u26A0\uFE0F Micropub endpoint not configured. Open plugin settings to add it.",noticeNoToken:"\u26A0\uFE0F Access token not configured. Open plugin settings to add it.",noticePublishing:"Publishing\u2026",noticePublished:"\u2705 Published!",noticePublishFailed:"\u274C Publish failed: {error}",noticeError:"\u274C Error: {error}",noticeNoSyndTargets:"\u26A0\uFE0F Could not fetch syndication targets. Publishing without dialog.",settingsTitle:"Micropub Publisher",settingsAccount:"Account",settingsEndpoints:"Endpoints",settingsEndpointsHint:"These are filled automatically when you sign in. Only edit them manually if your server uses non-standard paths.",settingsPublishBehaviour:"Publish Behaviour",settingsDigitalGarden:"Digital Garden",settingMicropubEndpoint:"Micropub endpoint",settingMicropubEndpointDesc:"e.g. https://example.com/micropub",settingMicropubEndpointPlaceholder:"https://example.com/micropub",settingMediaEndpoint:"Media endpoint",settingMediaEndpointDesc:"For image uploads. Auto-discovered if blank.",settingMediaEndpointPlaceholder:"https://example.com/micropub/media",settingVisibility:"Default visibility",settingVisibilityDesc:"Applies when the note has no explicit visibility property.",visibilityPublic:"Public",visibilityUnlisted:"Unlisted",visibilityPrivate:"Private",settingWriteUrl:"Write URL back to note",settingWriteUrlDesc:"After publishing, store the post URL as `mp-url` in frontmatter. Subsequent publishes will update the existing post instead of creating a new one.",settingSyndDialog:"Syndication dialog",settingSyndDialogDesc:"When to show the cross-posting dialog before publishing. 'When needed' shows it only if the note has no mp-syndicate-to frontmatter.",syndDialogWhenNeeded:"When needed",syndDialogAlways:"Always",syndDialogNever:"Never",settingSyndDefaults:"Default syndication targets",settingSyndDefaultsNone:"None configured. Targets checked by default in the publish dialog.",btnClearDefaults:"Clear defaults",settingGardenTags:"Map #garden/* tags to gardenStage",settingGardenTagsDesc:"Obsidian tags like #garden/plant become a `garden-stage: plant` Micropub property. The blog renders these as growth stage badges at /garden/.",settingGardenStages:"Stages: plant \u{1F331} \xB7 cultivate \u{1F33F} \xB7 question \u2753 \xB7 repot \u{1FAB4} \xB7 revitalize \u2728 \xB7 revisit \u{1F504}",settingSiteUrl:"Site URL",settingSiteUrlDesc:"Your site's home page. Clicking Sign in opens your blog's login page in the browser \u2014 the same flow iA Writer uses.",settingSiteUrlPlaceholder:"https://example.com",btnSignIn:"Sign in",btnOpeningBrowser:"Opening browser\u2026",noticeEnterSiteUrl:"Enter your site URL first.",noticeSignedInAs:"\u2705 Signed in as {me}",noticeSignInFailed:"Sign-in failed: {error}",lblSignedIn:"Signed in",btnSignOut:"Sign out",manualTokenSummary:"Or paste a token manually",settingAccessToken:"Access token",settingAccessTokenDesc:"Bearer token from your Indiekit admin panel.",settingAccessTokenPlaceholder:"your-bearer-token",btnVerify:"Verify",noticeSetEndpointFirst:"Set the Micropub endpoint and token first.",noticeTokenValid:"\u2705 Token is valid!",noticeTokenCheckFailed:"Token check failed: {error}",syndDialogTitle:"Syndication targets",syndDialogSubtitle:"Choose where to cross-post this note.",btnCancel:"Cancel",btnPublish:"Publish",errSignInTimeout:"Sign-in timed out (5 min). Please try again."};var Tt={cmdPublish:"An Micropub ver\xF6ffentlichen",cmdUpdate:"Bestehenden Micropub-Beitrag aktualisieren",noticeOpenNote:"\xD6ffne eine Markdown-Notiz zum Ver\xF6ffentlichen.",noticeNoEndpoint:"\u26A0\uFE0F Micropub-Endpunkt nicht konfiguriert. Bitte in den Plugin-Einstellungen eintragen.",noticeNoToken:"\u26A0\uFE0F Zugriffstoken nicht konfiguriert. Bitte in den Plugin-Einstellungen eintragen.",noticePublishing:"Wird ver\xF6ffentlicht\u2026",noticePublished:"\u2705 Ver\xF6ffentlicht!",noticePublishFailed:"\u274C Ver\xF6ffentlichung fehlgeschlagen: {error}",noticeError:"\u274C Fehler: {error}",noticeNoSyndTargets:"\u26A0\uFE0F Syndizierungsziele konnten nicht abgerufen werden. Ver\xF6ffentlichung ohne Dialog.",settingsTitle:"Micropub Publisher",settingsAccount:"Konto",settingsEndpoints:"Endpunkte",settingsEndpointsHint:"Diese werden beim Anmelden automatisch ausgef\xFCllt. Nur manuell bearbeiten, wenn der Server nicht standardm\xE4\xDFige Pfade verwendet.",settingsPublishBehaviour:"Ver\xF6ffentlichungsverhalten",settingsDigitalGarden:"Digitaler Garten",settingMicropubEndpoint:"Micropub-Endpunkt",settingMicropubEndpointDesc:"z. B. https://example.com/micropub",settingMicropubEndpointPlaceholder:"https://example.com/micropub",settingMediaEndpoint:"Medien-Endpunkt",settingMediaEndpointDesc:"F\xFCr Bild-Uploads. Wird automatisch ermittelt, wenn leer.",settingMediaEndpointPlaceholder:"https://example.com/micropub/media",settingVisibility:"Standard-Sichtbarkeit",settingVisibilityDesc:"Gilt, wenn die Notiz keine explizite Sichtbarkeits-Eigenschaft hat.",visibilityPublic:"\xD6ffentlich",visibilityUnlisted:"Nicht gelistet",visibilityPrivate:"Privat",settingWriteUrl:"URL zur\xFCck in Notiz schreiben",settingWriteUrlDesc:"Nach der Ver\xF6ffentlichung wird die Beitrags-URL als `mp-url` im Frontmatter gespeichert. Sp\xE4tere Ver\xF6ffentlichungen aktualisieren den Beitrag statt einen neuen zu erstellen.",settingSyndDialog:"Syndizierungsdialog",settingSyndDialogDesc:"Wann der Dialog zum Querverweis vor der Ver\xF6ffentlichung angezeigt wird. 'Bei Bedarf' zeigt ihn nur, wenn kein mp-syndicate-to im Frontmatter vorhanden ist.",syndDialogWhenNeeded:"Bei Bedarf",syndDialogAlways:"Immer",syndDialogNever:"Nie",settingSyndDefaults:"Standard-Syndizierungsziele",settingSyndDefaultsNone:"Keine konfiguriert. Im Ver\xF6ffentlichungsdialog standardm\xE4\xDFig aktivierte Ziele.",btnClearDefaults:"Standards l\xF6schen",settingGardenTags:"#garden/*-Tags zu gardenStage zuordnen",settingGardenTagsDesc:"Obsidian-Tags wie #garden/plant werden zur Micropub-Eigenschaft `garden-stage: plant`. Der Blog zeigt diese als Wachstumsstufen-Abzeichen unter /garden/ an.",settingGardenStages:"Stufen: plant \u{1F331} \xB7 cultivate \u{1F33F} \xB7 question \u2753 \xB7 repot \u{1FAB4} \xB7 revitalize \u2728 \xB7 revisit \u{1F504}",settingSiteUrl:"Website-URL",settingSiteUrlDesc:"Startseite deiner Website. Klick auf Anmelden \xF6ffnet die Login-Seite deines Blogs im Browser.",settingSiteUrlPlaceholder:"https://example.com",btnSignIn:"Anmelden",btnOpeningBrowser:"Browser wird ge\xF6ffnet\u2026",noticeEnterSiteUrl:"Bitte zuerst die Website-URL eingeben.",noticeSignedInAs:"\u2705 Angemeldet als {me}",noticeSignInFailed:"Anmeldung fehlgeschlagen: {error}",lblSignedIn:"Angemeldet",btnSignOut:"Abmelden",manualTokenSummary:"Oder Token manuell einf\xFCgen",settingAccessToken:"Zugriffstoken",settingAccessTokenDesc:"Bearer-Token aus deinem Indiekit-Adminbereich.",settingAccessTokenPlaceholder:"your-bearer-token",btnVerify:"Pr\xFCfen",noticeSetEndpointFirst:"Bitte zuerst Micropub-Endpunkt und Token eingeben.",noticeTokenValid:"\u2705 Token ist g\xFCltig!",noticeTokenCheckFailed:"Token-Pr\xFCfung fehlgeschlagen: {error}",syndDialogTitle:"Syndizierungsziele",syndDialogSubtitle:"Wo soll diese Notiz gleichzeitig ver\xF6ffentlicht werden?",btnCancel:"Abbrechen",btnPublish:"Ver\xF6ffentlichen",errSignInTimeout:"Anmeldung abgelaufen (5 Min.). Bitte erneut versuchen."};var L={en:kt,de:Tt};function o(g,t){var s,r,a,l,c;let e=((r=(s=window.moment)==null?void 0:s.locale())!=null?r:"en").split("-")[0],i=(c=(l=((a=L[e])!=null?a:L.en)[g])!=null?l:L.en[g])!=null?c:g;if(t)for(let[d,p]of Object.entries(t))i=i.split(`{${d}}`).join(p);return i}var Et="https://svemagie.github.io/obsidian-micropub/",Pt="https://svemagie.github.io/obsidian-micropub/callback",xt="create update media",zt=300*1e3,A=null;function Dt(g){if(!A)return;let{resolve:t,state:e}=A;A=null,t(g)}var F=class g{static async discoverEndpoints(t){let n=(await(0,G.requestUrl)({url:t,method:"GET"})).text,i=g.extractLinkRel(n,"authorization_endpoint"),s=g.extractLinkRel(n,"token_endpoint"),r=g.extractLinkRel(n,"micropub");if(!i)throw new Error(`No found at ${t}. Make sure Indiekit is running and SITE_URL is set correctly.`);if(!s)throw new Error(`No found at ${t}.`);return{authorizationEndpoint:i,tokenEndpoint:s,micropubEndpoint:r}}static async signIn(t){var b,E,S,P,R,x;let{authorizationEndpoint:e,tokenEndpoint:n,micropubEndpoint:i}=await g.discoverEndpoints(t),s=g.base64url(M.randomBytes(16)),r=g.base64url(M.randomBytes(64)),a=g.base64url(M.createHash("sha256").update(r).digest()),l=new Promise((C,D)=>{let v=setTimeout(()=>{A=null,D(new Error(o("errSignInTimeout")))},zt);A={state:s,resolve:N=>{clearTimeout(v),C(N)}}}),c=new URL(e);c.searchParams.set("response_type","code"),c.searchParams.set("client_id",Et),c.searchParams.set("redirect_uri",Pt),c.searchParams.set("state",s),c.searchParams.set("code_challenge",a),c.searchParams.set("code_challenge_method","S256"),c.searchParams.set("scope",xt),c.searchParams.set("me",t),window.open(c.toString());let d=await l;if(d.state!==s)throw new Error("State mismatch \u2014 possible CSRF attack. Please try again.");let p=d.code;if(!p)throw new Error((E=(b=d.error_description)!=null?b:d.error)!=null?E:"No authorization code received.");let u=await(0,G.requestUrl)({url:n,method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({grant_type:"authorization_code",code:p,client_id:Et,redirect_uri:Pt,code_verifier:r}).toString(),throw:!1}),h=u.json;if(!h.access_token)throw new Error((P=(S=h.error_description)!=null?S:h.error)!=null?P:`Token exchange failed (HTTP ${u.status})`);return{accessToken:h.access_token,scope:(R=h.scope)!=null?R:xt,me:(x=h.me)!=null?x:t,authorizationEndpoint:e,tokenEndpoint:n,micropubEndpoint:i}}static base64url(t){return t.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}static extractLinkRel(t,e){var s;let n=new RegExp(`]+rel=["'][^"']*\\b${e}\\b[^"']*["'][^>]+href=["']([^"']+)["']|]+href=["']([^"']+)["'][^>]+rel=["'][^"']*\\b${e}\\b[^"']*["']`,"i"),i=t.match(n);return(s=i==null?void 0:i[1])!=null?s:i==null?void 0:i[2]}};var $=class extends m.PluginSettingTab{constructor(e,n){super(e,n);this.plugin=n}display(){let{containerEl:e}=this;e.empty(),e.createEl("h2",{text:o("settingsTitle")}),e.createEl("h3",{text:o("settingsAccount")}),this.plugin.settings.me&&this.plugin.settings.accessToken?this.renderSignedIn(e):this.renderSignedOut(e),e.createEl("h3",{text:o("settingsEndpoints")}),e.createEl("p",{text:o("settingsEndpointsHint"),cls:"setting-item-description"}),new m.Setting(e).setName(o("settingMicropubEndpoint")).setDesc(o("settingMicropubEndpointDesc")).addText(s=>s.setPlaceholder(o("settingMicropubEndpointPlaceholder")).setValue(this.plugin.settings.micropubEndpoint).onChange(async r=>{this.plugin.settings.micropubEndpoint=r.trim(),await this.plugin.saveSettings()})),new m.Setting(e).setName(o("settingMediaEndpoint")).setDesc(o("settingMediaEndpointDesc")).addText(s=>s.setPlaceholder(o("settingMediaEndpointPlaceholder")).setValue(this.plugin.settings.mediaEndpoint).onChange(async r=>{this.plugin.settings.mediaEndpoint=r.trim(),await this.plugin.saveSettings()})),e.createEl("h3",{text:o("settingsPublishBehaviour")}),new m.Setting(e).setName(o("settingVisibility")).setDesc(o("settingVisibilityDesc")).addDropdown(s=>s.addOption("public",o("visibilityPublic")).addOption("unlisted",o("visibilityUnlisted")).addOption("private",o("visibilityPrivate")).setValue(this.plugin.settings.defaultVisibility).onChange(async r=>{this.plugin.settings.defaultVisibility=r,await this.plugin.saveSettings()})),new m.Setting(e).setName(o("settingWriteUrl")).setDesc(o("settingWriteUrlDesc")).addToggle(s=>s.setValue(this.plugin.settings.writeUrlToFrontmatter).onChange(async r=>{this.plugin.settings.writeUrlToFrontmatter=r,await this.plugin.saveSettings()})),new m.Setting(e).setName(o("settingSyndDialog")).setDesc(o("settingSyndDialogDesc")).addDropdown(s=>s.addOption("when-needed",o("syndDialogWhenNeeded")).addOption("always",o("syndDialogAlways")).addOption("never",o("syndDialogNever")).setValue(this.plugin.settings.showSyndicationDialog).onChange(async r=>{this.plugin.settings.showSyndicationDialog=r,await this.plugin.saveSettings()}));let n=this.plugin.settings.defaultSyndicateTo,i=new m.Setting(e).setName(o("settingSyndDefaults")).setDesc(n.length>0?n.join(", "):o("settingSyndDefaultsNone"));n.length>0&&i.addButton(s=>s.setButtonText(o("btnClearDefaults")).setWarning().onClick(async()=>{this.plugin.settings.defaultSyndicateTo=[],await this.plugin.saveSettings(),this.display()})),e.createEl("h3",{text:o("settingsDigitalGarden")}),new m.Setting(e).setName(o("settingGardenTags")).setDesc(o("settingGardenTagsDesc")).addToggle(s=>s.setValue(this.plugin.settings.mapGardenTags).onChange(async r=>{this.plugin.settings.mapGardenTags=r,await this.plugin.saveSettings()})),e.createEl("p",{text:o("settingGardenStages"),cls:"setting-item-description"})}renderSignedOut(e){new m.Setting(e).setName(o("settingSiteUrl")).setDesc(o("settingSiteUrlDesc")).addText(i=>i.setPlaceholder(o("settingSiteUrlPlaceholder")).setValue(this.plugin.settings.siteUrl).onChange(async s=>{this.plugin.settings.siteUrl=s.trim(),await this.plugin.saveSettings()})).addButton(i=>{i.setButtonText(o("btnSignIn")).setCta().onClick(async()=>{let s=this.plugin.settings.siteUrl.trim();if(!s){new m.Notice(o("noticeEnterSiteUrl"));return}i.setDisabled(!0),i.setButtonText(o("btnOpeningBrowser"));try{let r=await F.signIn(s);if(this.plugin.settings.accessToken=r.accessToken,this.plugin.settings.me=r.me,this.plugin.settings.authorizationEndpoint=r.authorizationEndpoint,this.plugin.settings.tokenEndpoint=r.tokenEndpoint,r.micropubEndpoint&&(this.plugin.settings.micropubEndpoint=r.micropubEndpoint),r.mediaEndpoint&&(this.plugin.settings.mediaEndpoint=r.mediaEndpoint),await this.plugin.saveSettings(),!this.plugin.settings.mediaEndpoint)try{let l=await new w(()=>this.plugin.settings.micropubEndpoint,()=>this.plugin.settings.mediaEndpoint,()=>this.plugin.settings.accessToken).fetchConfig();l["media-endpoint"]&&(this.plugin.settings.mediaEndpoint=l["media-endpoint"],await this.plugin.saveSettings())}catch(a){}new m.Notice(o("noticeSignedInAs",{me:r.me})),this.display()}catch(r){new m.Notice(o("noticeSignInFailed",{error:String(r)}),8e3),i.setDisabled(!1),i.setButtonText(o("btnSignIn"))}})});let n=e.createEl("details");n.createEl("summary",{text:o("manualTokenSummary"),cls:"setting-item-description"}),n.style.marginTop="8px",n.style.marginBottom="8px",new m.Setting(n).setName(o("settingAccessToken")).setDesc(o("settingAccessTokenDesc")).addText(i=>{i.setPlaceholder(o("settingAccessTokenPlaceholder")).setValue(this.plugin.settings.accessToken).onChange(async s=>{this.plugin.settings.accessToken=s.trim(),await this.plugin.saveSettings()}),i.inputEl.type="password"}).addButton(i=>i.setButtonText(o("btnVerify")).onClick(async()=>{if(!this.plugin.settings.micropubEndpoint||!this.plugin.settings.accessToken){new m.Notice(o("noticeSetEndpointFirst"));return}i.setDisabled(!0);try{await new w(()=>this.plugin.settings.micropubEndpoint,()=>this.plugin.settings.mediaEndpoint,()=>this.plugin.settings.accessToken).fetchConfig(),new m.Notice(o("noticeTokenValid"))}catch(s){new m.Notice(o("noticeTokenCheckFailed",{error:String(s)}))}finally{i.setDisabled(!1)}}))}renderSignedIn(e){let n=this.plugin.settings.me,i=e.createDiv({cls:"micropub-auth-banner"});i.style.cssText="display:flex;align-items:center;gap:12px;padding:12px 16px;border:1px solid var(--background-modifier-border);border-radius:8px;margin-bottom:16px;background:var(--background-secondary);";let s=i.createDiv();s.style.cssText="width:40px;height:40px;border-radius:50%;background:var(--interactive-accent);display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0;",s.textContent="\u{1F310}";let r=i.createDiv();r.createEl("div",{text:o("lblSignedIn"),attr:{style:"font-size:.75rem;color:var(--text-muted);margin-bottom:2px"}}),r.createEl("div",{text:n,attr:{style:"font-weight:500;word-break:break-all"}}),new m.Setting(e).setName(o("settingSiteUrl")).addText(a=>a.setValue(this.plugin.settings.siteUrl).setDisabled(!0)).addButton(a=>a.setButtonText(o("btnSignOut")).setWarning().onClick(async()=>{this.plugin.settings.accessToken="",this.plugin.settings.me="",this.plugin.settings.authorizationEndpoint="",this.plugin.settings.tokenEndpoint="",await this.plugin.saveSettings(),this.display()}))}};var At=require("obsidian");var V="garden/",z=class{constructor(t,e){this.app=t;this.settings=e;this.client=new w(()=>e.micropubEndpoint,()=>e.mediaEndpoint,()=>e.accessToken)}async publish(t,e){let n=await this.app.vault.read(t),{frontmatter:i,body:s}=this.parseFrontmatter(n),r=i["mp-url"]!=null?String(i["mp-url"]):i.url!=null?String(i.url):void 0,{content:a,uploadedUrls:l}=await this.processImages(s),c=this.resolveWikilinks(a,t.path),d=this.buildProperties(i,c,l,t.basename,t.path,e),p;if(r){let u={};for(let[h,b]of Object.entries(d))u[h]=Array.isArray(b)?b:[b];p=await this.client.updatePost(r,u)}else p=await this.client.createPost(d);return p.success&&this.settings.writeUrlToFrontmatter&&(p.url?await this.writeUrlToNote(t,n,p.url,e):e!==void 0&&await this.writeSyndicateToNote(t,n,e)),p}buildProperties(t,e,n,i,s,r){var Y,J,K,Z,Q,X,tt,et,it,nt,st,rt,ot,at,lt,ct,dt,gt,pt,ut,ht,mt,ft,bt,yt,wt;let a={},l=e.trim(),c=(Y=t.bookmarkOf)!=null?Y:t["bookmark-of"],d=(J=t.likeOf)!=null?J:t["like-of"],p=(K=t.inReplyTo)!=null?K:t["in-reply-to"],u=(Z=t.repostOf)!=null?Z:t["repost-of"];c&&(a["bookmark-of"]=[String(c)]),d&&(a["like-of"]=[String(d)]),p&&(a["in-reply-to"]=[String(p)]),u&&(a["repost-of"]=[String(u)]),(d||u)&&!l||(a.content=l?[{html:l}]:[{html:""}]);let b=(tt=(X=(Q=t.postType)!=null?Q:t.posttype)!=null?X:t["post-type"])!=null?tt:t.type;if(b==="article"||!b&&!!((et=t.title)!=null?et:t.name)){let f=(nt=(it=t.title)!=null?it:t.name)!=null?nt:i;a.name=[String(f)]}((st=t.summary)!=null?st:t.excerpt)&&(a.summary=[String((rt=t.summary)!=null?rt:t.excerpt)]);let S=(ot=t.created)!=null?ot:t.date;S&&(a.published=[new Date(String(S)).toISOString()]);let P=[...this.resolveArray(t.tags),...this.resolveArray(t.category)],R=this.extractGardenStage(P),x=P.filter(f=>!f.startsWith(V)&&f!=="garden");if(x.length>0&&(a.category=[...new Set(x)]),this.settings.mapGardenTags){let f=(at=t.gardenStage)!=null?at:R;if(f&&(a.gardenStage=[f],f==="evergreen")){let k=t["evergreen-since"];k&&(a.evergreenSince=[String(k)])}}let C=r!==void 0?r:[...new Set([...this.settings.defaultSyndicateTo,...this.resolveArray((lt=t["mp-syndicate-to"])!=null?lt:t.mpSyndicateTo)])];C.length>0&&(a["mp-syndicate-to"]=C);let D=(ct=t.visibility)!=null?ct:this.settings.defaultVisibility;D&&D!=="public"&&(a.visibility=[D]);let v=t.ai&&typeof t.ai=="object"?t.ai:{},N=(gt=(dt=t["ai-text-level"])!=null?dt:t.aiTextLevel)!=null?gt:v.textLevel,W=(ut=(pt=t["ai-code-level"])!=null?pt:t.aiCodeLevel)!=null?ut:v.codeLevel,j=(ft=(mt=(ht=t["ai-tools"])!=null?ht:t.aiTools)!=null?mt:v.aiTools)!=null?ft:v.tools,_=(wt=(yt=(bt=t["ai-description"])!=null?bt:t.aiDescription)!=null?yt:v.aiDescription)!=null?wt:v.description;N!=null&&(a["ai-text-level"]=[String(N)]),W!=null&&(a["ai-code-level"]=[String(W)]),j!=null&&(a["ai-tools"]=[String(j)]),_!=null&&(a["ai-description"]=[String(_)]);let H=this.resolvePhotoArray(t.photo);H.length>0&&(a.photo=H);let q=this.resolveArray(t.related);if(q.length>0){let f=q.map(k=>this.resolveWikilinkToUrl(k,s)).filter(k=>k!==null);f.length>0&&(a.related=f)}for(let[f,k]of Object.entries(t))f.startsWith("mp-")&&f!=="mp-url"&&f!=="mp-syndicate-to"&&(a[f]=this.resolveArray(k));return a}resolvePhotoArray(t){return t?(Array.isArray(t)?t:[t]).map(n=>{var i,s;if(typeof n=="string")return{value:n};if(typeof n=="object"&&n!==null){let r=n,a=String((s=(i=r.url)!=null?i:r.value)!=null?s:"");return a?r.alt?{value:a,alt:String(r.alt)}:{value:a}:null}return null}).filter(n=>n!==null):[]}extractGardenStage(t){for(let e of t){let n=e.replace(/^#/,"");if(n.startsWith(V)){let i=n.slice(V.length);if(["plant","cultivate","evergreen","question","repot","revitalize","revisit"].includes(i))return i}}}async processImages(t){let e=[],n=/!\[\[([^\]]+\.(png|jpg|jpeg|gif|webp|svg))\]\]/gi,i=/!\[([^\]]*)\]\(([^)]+\.(png|jpg|jpeg|gif|webp|svg))\)/gi,s=t,r=[...t.matchAll(n)];for(let l of r){let c=l[1];try{let d=await this.uploadLocalFile(c);d&&(e.push(d),s=s.replace(l[0],`![${c}](${d})`))}catch(d){console.warn(`[micropub] Failed to upload ${c}:`,d)}}let a=[...s.matchAll(i)];for(let l of a){let c=l[1],d=l[2];if(!d.startsWith("http"))try{let p=await this.uploadLocalFile(d);p&&(e.push(p),s=s.replace(l[0],`![${c}](${p})`))}catch(p){console.warn(`[micropub] Failed to upload ${d}:`,p)}}return{content:s,uploadedUrls:e}}async uploadLocalFile(t){let e=this.app.vault.getFiles().find(s=>s.name===t||s.path===t);if(!e)return;let n=await this.app.vault.readBinary(e),i=this.guessMimeType(e.extension);return this.client.uploadMedia(n,e.name,i)}parseFrontmatter(t){var i;let e=t.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!e)return{frontmatter:{},body:t};let n={};try{n=(i=(0,At.parseYaml)(e[1]))!=null?i:{}}catch(s){}return{frontmatter:n,body:e[2]}}async writeUrlToNote(t,e,n,i){var p;let s=new Date,r=[s.getFullYear(),String(s.getMonth()+1).padStart(2,"0"),String(s.getDate()).padStart(2,"0")].join("-"),a=[["mp-url",`"${n}"`],["post-status","published"],["published",r]];if(i!==void 0&&a.push(["mp-syndicate-to",`[${i.join(", ")}]`]),this.settings.siteUrl)try{let u=new URL(this.settings.siteUrl).hostname.replace(/^www\./,"");a.push(["medium",`"[[${u}]]"`])}catch(u){}{let{frontmatter:u}=this.parseFrontmatter(e);if(!u["evergreen-since"]){let h=[...this.resolveArray(u.tags),...this.resolveArray(u.category)];((p=u.gardenStage)!=null?p:this.extractGardenStage(h))==="evergreen"&&a.push(["evergreen-since",r])}}let l=e.match(/^(---\r?\n[\s\S]*?\r?\n---\r?\n)([\s\S]*)$/);if(!l){let u=a.map(([h,b])=>`${h}: ${b}`).join(` +`,l=new TextEncoder().encode(r),c=new TextEncoder().encode(a),d=new Uint8Array(t),p=new Uint8Array(l.length+d.length+c.length);p.set(l,0),p.set(d,l.length),p.set(c,l.length+d.length);let u=await(0,T.requestUrl)({url:i,method:"POST",headers:{...this.authHeaders(),"Content-Type":`multipart/form-data; boundary=${s}`},body:p.buffer,throw:!1});if(u.status===201||u.status===202){let v=((h=u.headers)==null?void 0:h.location)||((b=u.headers)==null?void 0:b.Location)||((E=u.json)==null?void 0:E.url);if(v)return v}throw new Error(`Media upload failed (HTTP ${u.status}): ${this.extractError(u.text)}`)}authHeaders(){return{Authorization:`Bearer ${this.getToken()}`}}extractLinkRel(t,e){var s;let n=new RegExp(`]+rel=["']${e}["'][^>]+href=["']([^"']+)["']|]+href=["']([^"']+)["'][^>]+rel=["']${e}["']`,"i"),i=t.match(n);return(s=i==null?void 0:i[1])!=null?s:i==null?void 0:i[2]}async fetchConfigFrom(t){return(await(0,T.requestUrl)({url:`${t}?q=config`,method:"GET",headers:this.authHeaders()})).json}extractError(t){var e,n;try{let i=JSON.parse(t);return(n=(e=i.error_description)!=null?e:i.error)!=null?n:t.slice(0,200)}catch(i){return t.slice(0,200)}}};var M=Ft(require("crypto")),V=require("obsidian");var Tt={cmdPublish:"Publish to Micropub",cmdUpdate:"Update existing Micropub post",noticeOpenNote:"Open a Markdown note to publish.",noticeNoEndpoint:"\u26A0\uFE0F Micropub endpoint not configured. Open plugin settings to add it.",noticeNoToken:"\u26A0\uFE0F Access token not configured. Open plugin settings to add it.",noticePublishing:"Publishing\u2026",noticePublished:"\u2705 Published!",noticePublishFailed:"\u274C Publish failed: {error}",noticeError:"\u274C Error: {error}",noticeNoSyndTargets:"\u26A0\uFE0F Could not fetch syndication targets. Publishing without dialog.",settingsTitle:"Micropub Publisher",settingsAccount:"Account",settingsEndpoints:"Endpoints",settingsEndpointsHint:"These are filled automatically when you sign in. Only edit them manually if your server uses non-standard paths.",settingsPublishBehaviour:"Publish Behaviour",settingsDigitalGarden:"Digital Garden",settingMicropubEndpoint:"Micropub endpoint",settingMicropubEndpointDesc:"e.g. https://example.com/micropub",settingMicropubEndpointPlaceholder:"https://example.com/micropub",settingMediaEndpoint:"Media endpoint",settingMediaEndpointDesc:"For image uploads. Auto-discovered if blank.",settingMediaEndpointPlaceholder:"https://example.com/micropub/media",settingVisibility:"Default visibility",settingVisibilityDesc:"Applies when the note has no explicit visibility property.",visibilityPublic:"Public",visibilityUnlisted:"Unlisted",visibilityPrivate:"Private",settingWriteUrl:"Write URL back to note",settingWriteUrlDesc:"After publishing, store the post URL as `mp-url` in frontmatter. Subsequent publishes will update the existing post instead of creating a new one.",settingSyndDialog:"Syndication dialog",settingSyndDialogDesc:"When to show the cross-posting dialog before publishing. 'When needed' shows it only if the note has no mp-syndicate-to frontmatter.",syndDialogWhenNeeded:"When needed",syndDialogAlways:"Always",syndDialogNever:"Never",settingSyndDefaults:"Default syndication targets",settingSyndDefaultsNone:"None configured. Targets checked by default in the publish dialog.",btnClearDefaults:"Clear defaults",settingGardenTags:"Map #garden/* tags to gardenStage",settingGardenTagsDesc:"Obsidian tags like #garden/plant become a `garden-stage: plant` Micropub property. The blog renders these as growth stage badges at /garden/.",settingGardenStages:"Stages: plant \u{1F331} \xB7 cultivate \u{1F33F} \xB7 question \u2753 \xB7 repot \u{1FAB4} \xB7 revitalize \u2728 \xB7 revisit \u{1F504}",settingSiteUrl:"Site URL",settingSiteUrlDesc:"Your site's home page. Clicking Sign in opens your blog's login page in the browser \u2014 the same flow iA Writer uses.",settingSiteUrlPlaceholder:"https://example.com",btnSignIn:"Sign in",btnOpeningBrowser:"Opening browser\u2026",noticeEnterSiteUrl:"Enter your site URL first.",noticeSignedInAs:"\u2705 Signed in as {me}",noticeSignInFailed:"Sign-in failed: {error}",lblSignedIn:"Signed in",btnSignOut:"Sign out",manualTokenSummary:"Or paste a token manually",settingAccessToken:"Access token",settingAccessTokenDesc:"Bearer token from your Indiekit admin panel.",settingAccessTokenPlaceholder:"your-bearer-token",btnVerify:"Verify",noticeSetEndpointFirst:"Set the Micropub endpoint and token first.",noticeTokenValid:"\u2705 Token is valid!",noticeTokenCheckFailed:"Token check failed: {error}",syndDialogTitle:"Syndication targets",syndDialogSubtitle:"Choose where to cross-post this note.",btnCancel:"Cancel",btnPublish:"Publish",errSignInTimeout:"Sign-in timed out (5 min). Please try again."};var Et={cmdPublish:"An Micropub ver\xF6ffentlichen",cmdUpdate:"Bestehenden Micropub-Beitrag aktualisieren",noticeOpenNote:"\xD6ffne eine Markdown-Notiz zum Ver\xF6ffentlichen.",noticeNoEndpoint:"\u26A0\uFE0F Micropub-Endpunkt nicht konfiguriert. Bitte in den Plugin-Einstellungen eintragen.",noticeNoToken:"\u26A0\uFE0F Zugriffstoken nicht konfiguriert. Bitte in den Plugin-Einstellungen eintragen.",noticePublishing:"Wird ver\xF6ffentlicht\u2026",noticePublished:"\u2705 Ver\xF6ffentlicht!",noticePublishFailed:"\u274C Ver\xF6ffentlichung fehlgeschlagen: {error}",noticeError:"\u274C Fehler: {error}",noticeNoSyndTargets:"\u26A0\uFE0F Syndizierungsziele konnten nicht abgerufen werden. Ver\xF6ffentlichung ohne Dialog.",settingsTitle:"Micropub Publisher",settingsAccount:"Konto",settingsEndpoints:"Endpunkte",settingsEndpointsHint:"Diese werden beim Anmelden automatisch ausgef\xFCllt. Nur manuell bearbeiten, wenn der Server nicht standardm\xE4\xDFige Pfade verwendet.",settingsPublishBehaviour:"Ver\xF6ffentlichungsverhalten",settingsDigitalGarden:"Digitaler Garten",settingMicropubEndpoint:"Micropub-Endpunkt",settingMicropubEndpointDesc:"z. B. https://example.com/micropub",settingMicropubEndpointPlaceholder:"https://example.com/micropub",settingMediaEndpoint:"Medien-Endpunkt",settingMediaEndpointDesc:"F\xFCr Bild-Uploads. Wird automatisch ermittelt, wenn leer.",settingMediaEndpointPlaceholder:"https://example.com/micropub/media",settingVisibility:"Standard-Sichtbarkeit",settingVisibilityDesc:"Gilt, wenn die Notiz keine explizite Sichtbarkeits-Eigenschaft hat.",visibilityPublic:"\xD6ffentlich",visibilityUnlisted:"Nicht gelistet",visibilityPrivate:"Privat",settingWriteUrl:"URL zur\xFCck in Notiz schreiben",settingWriteUrlDesc:"Nach der Ver\xF6ffentlichung wird die Beitrags-URL als `mp-url` im Frontmatter gespeichert. Sp\xE4tere Ver\xF6ffentlichungen aktualisieren den Beitrag statt einen neuen zu erstellen.",settingSyndDialog:"Syndizierungsdialog",settingSyndDialogDesc:"Wann der Dialog zum Querverweis vor der Ver\xF6ffentlichung angezeigt wird. 'Bei Bedarf' zeigt ihn nur, wenn kein mp-syndicate-to im Frontmatter vorhanden ist.",syndDialogWhenNeeded:"Bei Bedarf",syndDialogAlways:"Immer",syndDialogNever:"Nie",settingSyndDefaults:"Standard-Syndizierungsziele",settingSyndDefaultsNone:"Keine konfiguriert. Im Ver\xF6ffentlichungsdialog standardm\xE4\xDFig aktivierte Ziele.",btnClearDefaults:"Standards l\xF6schen",settingGardenTags:"#garden/*-Tags zu gardenStage zuordnen",settingGardenTagsDesc:"Obsidian-Tags wie #garden/plant werden zur Micropub-Eigenschaft `garden-stage: plant`. Der Blog zeigt diese als Wachstumsstufen-Abzeichen unter /garden/ an.",settingGardenStages:"Stufen: plant \u{1F331} \xB7 cultivate \u{1F33F} \xB7 question \u2753 \xB7 repot \u{1FAB4} \xB7 revitalize \u2728 \xB7 revisit \u{1F504}",settingSiteUrl:"Website-URL",settingSiteUrlDesc:"Startseite deiner Website. Klick auf Anmelden \xF6ffnet die Login-Seite deines Blogs im Browser.",settingSiteUrlPlaceholder:"https://example.com",btnSignIn:"Anmelden",btnOpeningBrowser:"Browser wird ge\xF6ffnet\u2026",noticeEnterSiteUrl:"Bitte zuerst die Website-URL eingeben.",noticeSignedInAs:"\u2705 Angemeldet als {me}",noticeSignInFailed:"Anmeldung fehlgeschlagen: {error}",lblSignedIn:"Angemeldet",btnSignOut:"Abmelden",manualTokenSummary:"Oder Token manuell einf\xFCgen",settingAccessToken:"Zugriffstoken",settingAccessTokenDesc:"Bearer-Token aus deinem Indiekit-Adminbereich.",settingAccessTokenPlaceholder:"your-bearer-token",btnVerify:"Pr\xFCfen",noticeSetEndpointFirst:"Bitte zuerst Micropub-Endpunkt und Token eingeben.",noticeTokenValid:"\u2705 Token ist g\xFCltig!",noticeTokenCheckFailed:"Token-Pr\xFCfung fehlgeschlagen: {error}",syndDialogTitle:"Syndizierungsziele",syndDialogSubtitle:"Wo soll diese Notiz gleichzeitig ver\xF6ffentlicht werden?",btnCancel:"Abbrechen",btnPublish:"Ver\xF6ffentlichen",errSignInTimeout:"Anmeldung abgelaufen (5 Min.). Bitte erneut versuchen."};var G={en:Tt,de:Et};function o(g,t){var s,r,a,l,c;let e=((r=(s=window.moment)==null?void 0:s.locale())!=null?r:"en").split("-")[0],i=(c=(l=((a=G[e])!=null?a:G.en)[g])!=null?l:G.en[g])!=null?c:g;if(t)for(let[d,p]of Object.entries(t))i=i.split(`{${d}}`).join(p);return i}var Pt="https://svemagie.github.io/obsidian-micropub/",xt="https://svemagie.github.io/obsidian-micropub/callback",Dt="create update media",Ot=300*1e3,A=null;function At(g){if(!A)return;let{resolve:t,state:e}=A;A=null,t(g)}var B=class g{static async discoverEndpoints(t){let n=(await(0,V.requestUrl)({url:t,method:"GET"})).text,i=g.extractLinkRel(n,"authorization_endpoint"),s=g.extractLinkRel(n,"token_endpoint"),r=g.extractLinkRel(n,"micropub");if(!i)throw new Error(`No found at ${t}. Make sure Indiekit is running and SITE_URL is set correctly.`);if(!s)throw new Error(`No found at ${t}.`);return{authorizationEndpoint:i,tokenEndpoint:s,micropubEndpoint:r}}static async signIn(t){var b,E,v,P,R,x;let{authorizationEndpoint:e,tokenEndpoint:n,micropubEndpoint:i}=await g.discoverEndpoints(t),s=g.base64url(M.randomBytes(16)),r=g.base64url(M.randomBytes(64)),a=g.base64url(M.createHash("sha256").update(r).digest()),l=new Promise((C,D)=>{let k=setTimeout(()=>{A=null,D(new Error(o("errSignInTimeout")))},Ot);A={state:s,resolve:N=>{clearTimeout(k),C(N)}}}),c=new URL(e);c.searchParams.set("response_type","code"),c.searchParams.set("client_id",Pt),c.searchParams.set("redirect_uri",xt),c.searchParams.set("state",s),c.searchParams.set("code_challenge",a),c.searchParams.set("code_challenge_method","S256"),c.searchParams.set("scope",Dt),c.searchParams.set("me",t),window.open(c.toString());let d=await l;if(d.state!==s)throw new Error("State mismatch \u2014 possible CSRF attack. Please try again.");let p=d.code;if(!p)throw new Error((E=(b=d.error_description)!=null?b:d.error)!=null?E:"No authorization code received.");let u=await(0,V.requestUrl)({url:n,method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"},body:new URLSearchParams({grant_type:"authorization_code",code:p,client_id:Pt,redirect_uri:xt,code_verifier:r}).toString(),throw:!1}),h=u.json;if(!h.access_token)throw new Error((P=(v=h.error_description)!=null?v:h.error)!=null?P:`Token exchange failed (HTTP ${u.status})`);return{accessToken:h.access_token,scope:(R=h.scope)!=null?R:Dt,me:(x=h.me)!=null?x:t,authorizationEndpoint:e,tokenEndpoint:n,micropubEndpoint:i}}static base64url(t){return t.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}static extractLinkRel(t,e){var s;let n=new RegExp(`]+rel=["'][^"']*\\b${e}\\b[^"']*["'][^>]+href=["']([^"']+)["']|]+href=["']([^"']+)["'][^>]+rel=["'][^"']*\\b${e}\\b[^"']*["']`,"i"),i=t.match(n);return(s=i==null?void 0:i[1])!=null?s:i==null?void 0:i[2]}};var F=class extends f.PluginSettingTab{constructor(e,n){super(e,n);this.plugin=n}display(){let{containerEl:e}=this;e.empty(),e.createEl("h2",{text:o("settingsTitle")}),e.createEl("h3",{text:o("settingsAccount")}),this.plugin.settings.me&&this.plugin.settings.accessToken?this.renderSignedIn(e):this.renderSignedOut(e),e.createEl("h3",{text:o("settingsEndpoints")}),e.createEl("p",{text:o("settingsEndpointsHint"),cls:"setting-item-description"}),new f.Setting(e).setName(o("settingMicropubEndpoint")).setDesc(o("settingMicropubEndpointDesc")).addText(s=>s.setPlaceholder(o("settingMicropubEndpointPlaceholder")).setValue(this.plugin.settings.micropubEndpoint).onChange(async r=>{this.plugin.settings.micropubEndpoint=r.trim(),await this.plugin.saveSettings()})),new f.Setting(e).setName(o("settingMediaEndpoint")).setDesc(o("settingMediaEndpointDesc")).addText(s=>s.setPlaceholder(o("settingMediaEndpointPlaceholder")).setValue(this.plugin.settings.mediaEndpoint).onChange(async r=>{this.plugin.settings.mediaEndpoint=r.trim(),await this.plugin.saveSettings()})),e.createEl("h3",{text:o("settingsPublishBehaviour")}),new f.Setting(e).setName(o("settingVisibility")).setDesc(o("settingVisibilityDesc")).addDropdown(s=>s.addOption("public",o("visibilityPublic")).addOption("unlisted",o("visibilityUnlisted")).addOption("private",o("visibilityPrivate")).setValue(this.plugin.settings.defaultVisibility).onChange(async r=>{this.plugin.settings.defaultVisibility=r,await this.plugin.saveSettings()})),new f.Setting(e).setName(o("settingWriteUrl")).setDesc(o("settingWriteUrlDesc")).addToggle(s=>s.setValue(this.plugin.settings.writeUrlToFrontmatter).onChange(async r=>{this.plugin.settings.writeUrlToFrontmatter=r,await this.plugin.saveSettings()})),new f.Setting(e).setName(o("settingSyndDialog")).setDesc(o("settingSyndDialogDesc")).addDropdown(s=>s.addOption("when-needed",o("syndDialogWhenNeeded")).addOption("always",o("syndDialogAlways")).addOption("never",o("syndDialogNever")).setValue(this.plugin.settings.showSyndicationDialog).onChange(async r=>{this.plugin.settings.showSyndicationDialog=r,await this.plugin.saveSettings()}));let n=this.plugin.settings.defaultSyndicateTo,i=new f.Setting(e).setName(o("settingSyndDefaults")).setDesc(n.length>0?n.join(", "):o("settingSyndDefaultsNone"));n.length>0&&i.addButton(s=>s.setButtonText(o("btnClearDefaults")).setWarning().onClick(async()=>{this.plugin.settings.defaultSyndicateTo=[],await this.plugin.saveSettings(),this.display()})),e.createEl("h3",{text:o("settingsDigitalGarden")}),new f.Setting(e).setName(o("settingGardenTags")).setDesc(o("settingGardenTagsDesc")).addToggle(s=>s.setValue(this.plugin.settings.mapGardenTags).onChange(async r=>{this.plugin.settings.mapGardenTags=r,await this.plugin.saveSettings()})),e.createEl("p",{text:o("settingGardenStages"),cls:"setting-item-description"})}renderSignedOut(e){new f.Setting(e).setName(o("settingSiteUrl")).setDesc(o("settingSiteUrlDesc")).addText(i=>i.setPlaceholder(o("settingSiteUrlPlaceholder")).setValue(this.plugin.settings.siteUrl).onChange(async s=>{this.plugin.settings.siteUrl=s.trim(),await this.plugin.saveSettings()})).addButton(i=>{i.setButtonText(o("btnSignIn")).setCta().onClick(async()=>{let s=this.plugin.settings.siteUrl.trim();if(!s){new f.Notice(o("noticeEnterSiteUrl"));return}i.setDisabled(!0),i.setButtonText(o("btnOpeningBrowser"));try{let r=await B.signIn(s);if(this.plugin.settings.accessToken=r.accessToken,this.plugin.settings.me=r.me,this.plugin.settings.authorizationEndpoint=r.authorizationEndpoint,this.plugin.settings.tokenEndpoint=r.tokenEndpoint,r.micropubEndpoint&&(this.plugin.settings.micropubEndpoint=r.micropubEndpoint),r.mediaEndpoint&&(this.plugin.settings.mediaEndpoint=r.mediaEndpoint),await this.plugin.saveSettings(),!this.plugin.settings.mediaEndpoint)try{let l=await new w(()=>this.plugin.settings.micropubEndpoint,()=>this.plugin.settings.mediaEndpoint,()=>this.plugin.settings.accessToken).fetchConfig();l["media-endpoint"]&&(this.plugin.settings.mediaEndpoint=l["media-endpoint"],await this.plugin.saveSettings())}catch(a){}new f.Notice(o("noticeSignedInAs",{me:r.me})),this.display()}catch(r){new f.Notice(o("noticeSignInFailed",{error:String(r)}),8e3),i.setDisabled(!1),i.setButtonText(o("btnSignIn"))}})});let n=e.createEl("details");n.createEl("summary",{text:o("manualTokenSummary"),cls:"setting-item-description"}),n.style.marginTop="8px",n.style.marginBottom="8px",new f.Setting(n).setName(o("settingAccessToken")).setDesc(o("settingAccessTokenDesc")).addText(i=>{i.setPlaceholder(o("settingAccessTokenPlaceholder")).setValue(this.plugin.settings.accessToken).onChange(async s=>{this.plugin.settings.accessToken=s.trim(),await this.plugin.saveSettings()}),i.inputEl.type="password"}).addButton(i=>i.setButtonText(o("btnVerify")).onClick(async()=>{if(!this.plugin.settings.micropubEndpoint||!this.plugin.settings.accessToken){new f.Notice(o("noticeSetEndpointFirst"));return}i.setDisabled(!0);try{await new w(()=>this.plugin.settings.micropubEndpoint,()=>this.plugin.settings.mediaEndpoint,()=>this.plugin.settings.accessToken).fetchConfig(),new f.Notice(o("noticeTokenValid"))}catch(s){new f.Notice(o("noticeTokenCheckFailed",{error:String(s)}))}finally{i.setDisabled(!1)}}))}renderSignedIn(e){let n=this.plugin.settings.me,i=e.createDiv({cls:"micropub-auth-banner"});i.style.cssText="display:flex;align-items:center;gap:12px;padding:12px 16px;border:1px solid var(--background-modifier-border);border-radius:8px;margin-bottom:16px;background:var(--background-secondary);";let s=i.createDiv();s.style.cssText="width:40px;height:40px;border-radius:50%;background:var(--interactive-accent);display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0;",s.textContent="\u{1F310}";let r=i.createDiv();r.createEl("div",{text:o("lblSignedIn"),attr:{style:"font-size:.75rem;color:var(--text-muted);margin-bottom:2px"}}),r.createEl("div",{text:n,attr:{style:"font-weight:500;word-break:break-all"}}),new f.Setting(e).setName(o("settingSiteUrl")).addText(a=>a.setValue(this.plugin.settings.siteUrl).setDisabled(!0)).addButton(a=>a.setButtonText(o("btnSignOut")).setWarning().onClick(async()=>{this.plugin.settings.accessToken="",this.plugin.settings.me="",this.plugin.settings.authorizationEndpoint="",this.plugin.settings.tokenEndpoint="",await this.plugin.saveSettings(),this.display()}))}};var Mt=require("obsidian");var W="garden/",z=class{constructor(t,e){this.app=t;this.settings=e;this.client=new w(()=>e.micropubEndpoint,()=>e.mediaEndpoint,()=>e.accessToken)}async publish(t,e){let n=await this.app.vault.read(t),{frontmatter:i,body:s}=this.parseFrontmatter(n),r=i["mp-url"]!=null?String(i["mp-url"]):i.url!=null?String(i.url):void 0,{content:a,uploadedUrls:l}=await this.processImages(s),c=this.resolveWikilinks(a,t.path),d=this.buildProperties(i,c,l,t.basename,t.path,e),p;if(r){let u={};for(let[h,b]of Object.entries(d))u[h]=Array.isArray(b)?b:[b];p=await this.client.updatePost(r,u)}else p=await this.client.createPost(d);return p.success&&this.settings.writeUrlToFrontmatter&&(p.url?await this.writeUrlToNote(t,n,p.url,e):e!==void 0&&await this.writeSyndicateToNote(t,n,e)),p}buildProperties(t,e,n,i,s,r){var J,K,Z,Q,X,tt,et,it,nt,st,rt,ot,at,lt,ct,dt,gt,pt,ut,ht,mt,ft,bt,yt,St,wt;let a={},l=e.trim(),c=(J=t.bookmarkOf)!=null?J:t["bookmark-of"],d=(K=t.likeOf)!=null?K:t["like-of"],p=(Z=t.inReplyTo)!=null?Z:t["in-reply-to"],u=(Q=t.repostOf)!=null?Q:t["repost-of"];c&&(a["bookmark-of"]=[String(c)]),d&&(a["like-of"]=[String(d)]),p&&(a["in-reply-to"]=[String(p)]),u&&(a["repost-of"]=[String(u)]),(d||u)&&!l||(a.content=l?[{text:l}]:[{text:""}]);let b=(et=(tt=(X=t.postType)!=null?X:t.posttype)!=null?tt:t["post-type"])!=null?et:t.type;if(b==="article"||!b&&!!((it=t.title)!=null?it:t.name)){let m=(st=(nt=t.title)!=null?nt:t.name)!=null?st:i;a.name=[String(m)]}((rt=t.summary)!=null?rt:t.excerpt)&&(a.summary=[String((ot=t.summary)!=null?ot:t.excerpt)]);let v=(at=t.created)!=null?at:t.date;if(v){let m=String(v),S;if(/^\d{4}-\d{2}-\d{2}$/.test(m)){let L=new Date;S=new Date(`${m}T${String(L.getHours()).padStart(2,"0")}:${String(L.getMinutes()).padStart(2,"0")}:${String(L.getSeconds()).padStart(2,"0")}`)}else S=new Date(m);a.published=[S.toISOString()]}let P=[...this.resolveArray(t.tags),...this.resolveArray(t.category)],R=this.extractGardenStage(P),x=P.filter(m=>!m.startsWith(W)&&m!=="garden");if(x.length>0&&(a.category=[...new Set(x)]),this.settings.mapGardenTags){let m=(lt=t.gardenStage)!=null?lt:R;if(m&&(a.gardenStage=[m],m==="evergreen")){let S=t["evergreen-since"];S&&(a.evergreenSince=[String(S)])}}let C=r!==void 0?r:[...new Set([...this.settings.defaultSyndicateTo,...this.resolveArray((ct=t["mp-syndicate-to"])!=null?ct:t.mpSyndicateTo)])];C.length>0&&(a["mp-syndicate-to"]=C);let D=(dt=t.visibility)!=null?dt:this.settings.defaultVisibility;D&&D!=="public"&&(a.visibility=[D]);let k=t.ai&&typeof t.ai=="object"?t.ai:{},N=(pt=(gt=t["ai-text-level"])!=null?gt:t.aiTextLevel)!=null?pt:k.textLevel,j=(ht=(ut=t["ai-code-level"])!=null?ut:t.aiCodeLevel)!=null?ht:k.codeLevel,_=(bt=(ft=(mt=t["ai-tools"])!=null?mt:t.aiTools)!=null?ft:k.aiTools)!=null?bt:k.tools,H=(wt=(St=(yt=t["ai-description"])!=null?yt:t.aiDescription)!=null?St:k.aiDescription)!=null?wt:k.description;N!=null&&(a["ai-text-level"]=[String(N)]),j!=null&&(a["ai-code-level"]=[String(j)]),_!=null&&(a["ai-tools"]=[String(_)]),H!=null&&(a["ai-description"]=[String(H)]);let q=this.resolvePhotoArray(t.photo);q.length>0&&(a.photo=q);let Y=this.resolveArray(t.related);if(Y.length>0){let m=Y.map(S=>this.resolveWikilinkToUrl(S,s)).filter(S=>S!==null);m.length>0&&(a.related=m)}for(let[m,S]of Object.entries(t))m.startsWith("mp-")&&m!=="mp-url"&&m!=="mp-syndicate-to"&&(a[m]=this.resolveArray(S));return a}resolvePhotoArray(t){return t?(Array.isArray(t)?t:[t]).map(n=>{var i,s;if(typeof n=="string")return{value:n};if(typeof n=="object"&&n!==null){let r=n,a=String((s=(i=r.url)!=null?i:r.value)!=null?s:"");return a?r.alt?{value:a,alt:String(r.alt)}:{value:a}:null}return null}).filter(n=>n!==null):[]}extractGardenStage(t){for(let e of t){let n=e.replace(/^#/,"");if(n.startsWith(W)){let i=n.slice(W.length);if(["plant","cultivate","evergreen","question","repot","revitalize","revisit"].includes(i))return i}}}async processImages(t){let e=[],n=/!\[\[([^\]]+\.(png|jpg|jpeg|gif|webp|svg))\]\]/gi,i=/!\[([^\]]*)\]\(([^)]+\.(png|jpg|jpeg|gif|webp|svg))\)/gi,s=t,r=[...t.matchAll(n)];for(let l of r){let c=l[1];try{let d=await this.uploadLocalFile(c);d&&(e.push(d),s=s.replace(l[0],`![${c}](${d})`))}catch(d){console.warn(`[micropub] Failed to upload ${c}:`,d)}}let a=[...s.matchAll(i)];for(let l of a){let c=l[1],d=l[2];if(!d.startsWith("http"))try{let p=await this.uploadLocalFile(d);p&&(e.push(p),s=s.replace(l[0],`![${c}](${p})`))}catch(p){console.warn(`[micropub] Failed to upload ${d}:`,p)}}return{content:s,uploadedUrls:e}}async uploadLocalFile(t){let e=this.app.vault.getFiles().find(s=>s.name===t||s.path===t);if(!e)return;let n=await this.app.vault.readBinary(e),i=this.guessMimeType(e.extension);return this.client.uploadMedia(n,e.name,i)}parseFrontmatter(t){var i;let e=t.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!e)return{frontmatter:{},body:t};let n={};try{n=(i=(0,Mt.parseYaml)(e[1]))!=null?i:{}}catch(s){}return{frontmatter:n,body:e[2]}}async writeUrlToNote(t,e,n,i){var p;let s=new Date,r=[s.getFullYear(),String(s.getMonth()+1).padStart(2,"0"),String(s.getDate()).padStart(2,"0")].join("-")+"T"+String(s.getHours()).padStart(2,"0")+":"+String(s.getMinutes()).padStart(2,"0")+":"+String(s.getSeconds()).padStart(2,"0"),a=[["mp-url",`"${n}"`],["post-status","published"],["published",r]];if(i!==void 0&&a.push(["mp-syndicate-to",`[${i.join(", ")}]`]),this.settings.siteUrl)try{let u=new URL(this.settings.siteUrl).hostname.replace(/^www\./,"");a.push(["medium",`"[[${u}]]"`])}catch(u){}{let{frontmatter:u}=this.parseFrontmatter(e);if(!u["evergreen-since"]){let h=[...this.resolveArray(u.tags),...this.resolveArray(u.category)];((p=u.gardenStage)!=null?p:this.extractGardenStage(h))==="evergreen"&&a.push(["evergreen-since",r])}}let l=e.match(/^(---\r?\n[\s\S]*?\r?\n---\r?\n)([\s\S]*)$/);if(!l){let u=a.map(([h,b])=>`${h}: ${b}`).join(` `);await this.app.vault.modify(t,`--- ${u} --- @@ -17,5 +17,5 @@ ${u} mp-syndicate-to: ${s} --- `+e);return}let r=this.setFrontmatterField(i[1],"mp-syndicate-to",s);await this.app.vault.modify(t,r+i[2])}setFrontmatterField(t,e,n){let i=new RegExp(`^${e}:.*$`,"m");return i.test(t)?t.replace(i,`${e}: ${n}`):t.replace(/(\r?\n---\r?\n)$/,` -${e}: ${n}$1`)}resolveWikilinks(t,e){return t.replace(/(?{let a=i.trim(),l=(r==null?void 0:r.trim())||a.split("/").pop()||a,c=this.resolveWikilinkToUrl(`[[${a}]]`,e);if(!c)return l;let d=s?s.toLowerCase().replace(/\s+/g,"-"):"";return`[${l}](${c}${d})`})}resolveWikilinkToUrl(t,e){var s,r,a;if(t.startsWith("http"))return t;let n=t.match(/^\[\[([^\]|#]+)(?:#[^\]|]*)?\|?[^\]]*\]\]$/);if(!n)return null;let i=this.app.metadataCache.getFirstLinkpathDest(n[1].trim(),e);return i&&(a=(r=(s=this.app.metadataCache.getFileCache(i))==null?void 0:s.frontmatter)==null?void 0:r["mp-url"])!=null?a:null}resolveArray(t){return t?Array.isArray(t)?t.map(String):[String(t)]:[]}guessMimeType(t){var n;return(n={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml"}[t.toLowerCase()])!=null?n:"application/octet-stream"}};var U=require("obsidian");var O=class extends U.Modal{constructor(e,n,i){super(e);this.targets=n;this.resolvePromise=null;this.resolved=!1;this.selected=new Set(i.filter(s=>n.some(r=>r.uid===s)))}async awaitSelection(){return new Promise(e=>{this.resolvePromise=e,this.open()})}onOpen(){let{contentEl:e}=this;e.createEl("h2",{text:o("syndDialogTitle")}),e.createEl("p",{text:o("syndDialogSubtitle"),cls:"setting-item-description"});for(let n of this.targets)new U.Setting(e).setName(n.name).addToggle(i=>i.setValue(this.selected.has(n.uid)).onChange(s=>{s?this.selected.add(n.uid):this.selected.delete(n.uid)}));new U.Setting(e).addButton(n=>n.setButtonText(o("btnCancel")).onClick(()=>{this.finish(null)})).addButton(n=>n.setButtonText(o("btnPublish")).setCta().onClick(()=>{this.finish([...this.selected])}))}onClose(){this.finish(null),this.contentEl.empty()}finish(e){var n;this.resolved||(this.resolved=!0,(n=this.resolvePromise)==null||n.call(this,e),this.resolvePromise=null)}};var I=class extends y.Plugin{async onload(){await this.loadSettings(),this.addCommand({id:"publish-to-micropub",name:o("cmdPublish"),checkCallback:t=>{let e=this.app.workspace.getActiveFile();return!e||e.extension!=="md"?!1:(t||this.publishActiveNote(e),!0)}}),this.addCommand({id:"publish-to-micropub-update",name:o("cmdUpdate"),checkCallback:t=>{let e=this.app.workspace.getActiveFile();return!e||e.extension!=="md"?!1:(t||this.publishActiveNote(e),!0)}}),this.registerObsidianProtocolHandler("micropub-auth",t=>{Dt(t)}),this.addSettingTab(new $(this.app,this)),this.addRibbonIcon("send",o("cmdPublish"),()=>{let t=this.app.workspace.getActiveFile();if(!t||t.extension!=="md"){new y.Notice(o("noticeOpenNote"));return}this.publishActiveNote(t)})}onunload(){}async publishActiveNote(t){var i;if(!this.settings.micropubEndpoint){new y.Notice(o("noticeNoEndpoint"));return}if(!this.settings.accessToken){new y.Notice(o("noticeNoToken"));return}let e=await this.resolveSyndicationTargets(t);if(e===null)return;let n=new y.Notice(o("noticePublishing"),0);try{let r=await new z(this.app,this.settings).publish(t,e);if(n.hide(),r.success){let a=r.url?` -${r.url}`:"";new y.Notice(`${o("noticePublished")}${a}`,8e3)}else new y.Notice(o("noticePublishFailed",{error:(i=r.error)!=null?i:""}),1e4),console.error("[micropub] Publish failed:",r.error)}catch(s){n.hide();let r=s instanceof Error?s.message:String(s);new y.Notice(o("noticeError",{error:r}),1e4),console.error("[micropub] Unexpected error:",s)}}async resolveSyndicationTargets(t){var l,c;let e=this.settings.showSyndicationDialog;if(e==="never")return;let n=[];try{n=(l=(await new w(()=>this.settings.micropubEndpoint,()=>this.settings.mediaEndpoint,()=>this.settings.accessToken).fetchConfig())["syndicate-to"])!=null?l:[]}catch(d){new y.Notice(o("noticeNoSyndTargets"),4e3);return}if(n.length===0)return;let i;try{let p=(await this.app.vault.read(t)).match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);if(p){let h=((c=(0,y.parseYaml)(p[1]))!=null?c:{})["mp-syndicate-to"];h!==void 0&&(i=Array.isArray(h)?h.map(String):[String(h)])}}catch(d){}if(!(e==="always"||e==="when-needed"&&i===void 0||i!==void 0&&i.length===0))return;let r=i&&i.length>0?i:this.settings.defaultSyndicateTo;return new O(this.app,n,r).awaitSelection()}async loadSettings(){this.settings=Object.assign({},vt,await this.loadData())}async saveSettings(){await this.saveData(this.settings)}}; +${e}: ${n}$1`)}resolveWikilinks(t,e){return t.replace(/(?{let a=i.trim(),l=(r==null?void 0:r.trim())||a.split("/").pop()||a,c=this.resolveWikilinkToUrl(`[[${a}]]`,e);if(!c)return l;let d=s?s.toLowerCase().replace(/\s+/g,"-"):"";return`[${l}](${c}${d})`})}resolveWikilinkToUrl(t,e){var s,r,a;if(t.startsWith("http"))return t;let n=t.match(/^\[\[([^\]|#]+)(?:#[^\]|]*)?\|?[^\]]*\]\]$/);if(!n)return null;let i=this.app.metadataCache.getFirstLinkpathDest(n[1].trim(),e);return i&&(a=(r=(s=this.app.metadataCache.getFileCache(i))==null?void 0:s.frontmatter)==null?void 0:r["mp-url"])!=null?a:null}resolveArray(t){return t?Array.isArray(t)?t.map(String):[String(t)]:[]}guessMimeType(t){var n;return(n={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml"}[t.toLowerCase()])!=null?n:"application/octet-stream"}};var U=require("obsidian");var O=class extends U.Modal{constructor(e,n,i){super(e);this.targets=n;this.resolvePromise=null;this.resolved=!1;this.selected=new Set(i.filter(s=>n.some(r=>r.uid===s)))}async awaitSelection(){return new Promise(e=>{this.resolvePromise=e,this.open()})}onOpen(){let{contentEl:e}=this;e.createEl("h2",{text:o("syndDialogTitle")}),e.createEl("p",{text:o("syndDialogSubtitle"),cls:"setting-item-description"});for(let n of this.targets)new U.Setting(e).setName(n.name).addToggle(i=>i.setValue(this.selected.has(n.uid)).onChange(s=>{s?this.selected.add(n.uid):this.selected.delete(n.uid)}));new U.Setting(e).addButton(n=>n.setButtonText(o("btnCancel")).onClick(()=>{this.finish(null)})).addButton(n=>n.setButtonText(o("btnPublish")).setCta().onClick(()=>{this.finish([...this.selected])}))}onClose(){this.finish(null),this.contentEl.empty()}finish(e){var n;this.resolved||(this.resolved=!0,(n=this.resolvePromise)==null||n.call(this,e),this.resolvePromise=null)}};var I=class extends y.Plugin{async onload(){await this.loadSettings(),this.addCommand({id:"publish-to-micropub",name:o("cmdPublish"),checkCallback:t=>{let e=this.app.workspace.getActiveFile();return!e||e.extension!=="md"?!1:(t||this.publishActiveNote(e),!0)}}),this.addCommand({id:"publish-to-micropub-update",name:o("cmdUpdate"),checkCallback:t=>{let e=this.app.workspace.getActiveFile();return!e||e.extension!=="md"?!1:(t||this.publishActiveNote(e),!0)}}),this.registerObsidianProtocolHandler("micropub-auth",t=>{At(t)}),this.addSettingTab(new F(this.app,this)),this.addRibbonIcon("send",o("cmdPublish"),()=>{let t=this.app.workspace.getActiveFile();if(!t||t.extension!=="md"){new y.Notice(o("noticeOpenNote"));return}this.publishActiveNote(t)})}onunload(){}async publishActiveNote(t){var i;if(!this.settings.micropubEndpoint){new y.Notice(o("noticeNoEndpoint"));return}if(!this.settings.accessToken){new y.Notice(o("noticeNoToken"));return}let e=await this.resolveSyndicationTargets(t);if(e===null)return;let n=new y.Notice(o("noticePublishing"),0);try{let r=await new z(this.app,this.settings).publish(t,e);if(n.hide(),r.success){let a=r.url?` +${r.url}`:"";new y.Notice(`${o("noticePublished")}${a}`,8e3)}else new y.Notice(o("noticePublishFailed",{error:(i=r.error)!=null?i:""}),1e4),console.error("[micropub] Publish failed:",r.error)}catch(s){n.hide();let r=s instanceof Error?s.message:String(s);new y.Notice(o("noticeError",{error:r}),1e4),console.error("[micropub] Unexpected error:",s)}}async resolveSyndicationTargets(t){var l,c;let e=this.settings.showSyndicationDialog;if(e==="never")return;let n=[];try{n=(l=(await new w(()=>this.settings.micropubEndpoint,()=>this.settings.mediaEndpoint,()=>this.settings.accessToken).fetchConfig())["syndicate-to"])!=null?l:[]}catch(d){new y.Notice(o("noticeNoSyndTargets"),4e3);return}if(n.length===0)return;let i;try{let p=(await this.app.vault.read(t)).match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);if(p){let h=((c=(0,y.parseYaml)(p[1]))!=null?c:{})["mp-syndicate-to"];h!==void 0&&(i=Array.isArray(h)?h.map(String):[String(h)])}}catch(d){}if(!(e==="always"||e==="when-needed"&&i===void 0||i!==void 0&&i.length===0))return;let r=i&&i.length>0?i:this.settings.defaultSyndicateTo;return new O(this.app,n,r).awaitSelection()}async loadSettings(){this.settings=Object.assign({},kt,await this.loadData())}async saveSettings(){await this.saveData(this.settings)}}; diff --git a/src/Publisher.ts b/src/Publisher.ts index d70a7db..cb6a567 100644 --- a/src/Publisher.ts +++ b/src/Publisher.ts @@ -115,7 +115,7 @@ export class Publisher { const isInteractionWithoutBody = (likeOf || repostOf) && !trimmedBody; if (!isInteractionWithoutBody) { - props["content"] = trimmedBody ? [{ html: trimmedBody }] : [{ html: "" }]; + props["content"] = trimmedBody ? [{ text: trimmedBody }] : [{ text: "" }]; } // ── Standard properties ─────────────────────────────────────────────── @@ -141,10 +141,24 @@ export class Publisher { props["summary"] = [String(fm["summary"] ?? fm["excerpt"])]; } - // Published date — prefer `created` (Obsidian default), fall back to `date` + // Published date — prefer `created` (Obsidian default), fall back to `date`. + // Date-only strings (YYYY-MM-DD) are parsed as UTC midnight by the Date + // constructor; append the current local time so the published timestamp + // reflects when the post was actually sent. const rawDate = fm["created"] ?? fm["date"]; if (rawDate) { - props["published"] = [new Date(String(rawDate)).toISOString()]; + const dateStr = String(rawDate); + let published: Date; + if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) { + // Date-only: combine with current local time + const now = new Date(); + published = new Date( + `${dateStr}T${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}`, + ); + } else { + published = new Date(dateStr); + } + props["published"] = [published.toISOString()]; } // Categories from frontmatter `category` AND `tags` (excluding garden/* tags). @@ -393,7 +407,13 @@ export class Publisher { now.getFullYear(), String(now.getMonth() + 1).padStart(2, "0"), String(now.getDate()).padStart(2, "0"), - ].join("-"); + ].join("-") + + "T" + + String(now.getHours()).padStart(2, "0") + + ":" + + String(now.getMinutes()).padStart(2, "0") + + ":" + + String(now.getSeconds()).padStart(2, "0"); const fields: Array<[string, string]> = [ ["mp-url", `"${url}"`],