@mdfriday/foundry 26.4.14 → 26.4.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
1
  /* @mdfriday/foundry - Obsidian Mobile (standalone) */
2
- var BrowserLogger,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__esm=(e,t)=>function(){return e&&(t=(0,e[__getOwnPropNames(e)[0]])(e=0)),t},__export=(e,t)=>{for(var i in t)__defProp(e,i,{get:t[i],enumerable:!0})},__publicField=(e,t,i)=>(((e,t,i)=>{t in e?__defProp(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i})(e,"symbol"!=typeof t?t+"":t,i),i),init_types=__esm({"pkg/log/types.ts"(){}});function NewBrowser(e="info"){return new BrowserLogger({level:e})}function NewBrowserWithConfig(e){return new BrowserLogger(e)}var globalBrowserLoggerManager,init_browser=__esm({"pkg/log/browser.ts"(){init_types(),BrowserLogger=class e{constructor(e){__publicField(this,"config"),__publicField(this,"fields"),this.config={enableCaller:!1,jsonFormat:!1,...e},this.fields={}}shouldLog(e){const t=["debug","info","warn","error","fatal"],i=t.indexOf(this.config.level);return t.indexOf(e)>=i}getCaller(){if(this.config.enableCaller)try{const e=(new Error).stack;if(!e)return;const t=e.split("\n")[4];if(!t)return;const i=t.match(/at .* \((.+):(\d+):(\d+)\)/);if(i){const[,e,t]=i;return`${e.split("/").pop()}:${t}`}const s=t.match(/at (.+):(\d+):(\d+)/);if(s){const[,e,t]=s;return`${e.split("/").pop()}:${t}`}return}catch{return}}formatMessage(e,t){if(0===t.length)return e;let i=e,s=0;for(i=i.replace(/%[sdj]/g,e=>{if(s>=t.length)return e;const i=t[s++];switch(e){case"%s":return String(i);case"%d":return Number(i).toString();case"%j":try{return JSON.stringify(i)}catch{return"[Circular]"}default:return e}});s<t.length;)i+=" "+String(t[s++]);return i}writeLog(e,t){if(!this.shouldLog(e))return;const i={level:e,timestamp:(new Date).toISOString(),message:t,...this.fields},s=this.getCaller();if(s&&(i.caller=s),this.config.jsonFormat){const t=JSON.stringify(i);this.consoleOutput(e,t)}else{const t=this.formatPlainText(i);this.consoleOutput(e,t)}}consoleOutput(e,t){switch(e){case"debug":break;case"info":console.log(t);break;case"warn":console.warn(t);break;case"error":console.error(t);break;case"fatal":console.error("[FATAL]",t)}}formatPlainText(e){const t=[e.timestamp,e.level.toUpperCase()];e.caller&&t.push(`[${e.caller}]`),t.push(e.message);const i=Object.keys(e).filter(e=>!["level","timestamp","message","caller"].includes(e)).map(t=>`${t}=${JSON.stringify(e[t])}`).join(" ");return i&&t.push(i),t.join(" ")}debug(e,...t){this.writeLog("debug",this.formatMessage(e,t))}info(e,...t){this.writeLog("info",this.formatMessage(e,t))}warn(e,...t){this.writeLog("warn",this.formatMessage(e,t))}error(e,...t){this.writeLog("error",this.formatMessage(e,t))}fatal(e,...t){this.writeLog("fatal",this.formatMessage(e,t))}debugf(e,...t){this.writeLog("debug",this.formatMessage(e,t))}infof(e,...t){this.writeLog("info",this.formatMessage(e,t))}warnf(e,...t){this.writeLog("warn",this.formatMessage(e,t))}errorf(e,...t){this.writeLog("error",this.formatMessage(e,t))}fatalf(e,...t){this.writeLog("fatal",this.formatMessage(e,t))}with(t){const i=new e(this.config);return i.fields={...this.fields,...t},i}}}});function getDomainLogger(e,t){return globalBrowserLoggerManager.getDomainLogger(e,t)}var Email,Token,ServerConfig,License,SyncConfig,Device,User,log4,UserFactory,init_browser_manager=__esm({"pkg/log/browser-manager.ts"(){init_browser(),init_types(),globalBrowserLoggerManager=new class{constructor(){__publicField(this,"globalLogger"),__publicField(this,"domainLoggers"),this.globalLogger=NewBrowser("info"),this.domainLoggers=new Map}setGlobalLogLevel(e){this.globalLogger=NewBrowser(e),this.domainLoggers.clear()}setGlobalCallerEnabled(e){this.globalLogger=NewBrowserWithConfig({level:"info",enableCaller:e}),this.domainLoggers.clear()}setGlobalJsonFormat(e){this.globalLogger=NewBrowserWithConfig({level:"info",jsonFormat:e}),this.domainLoggers.clear()}getDomainLogger(e,t){const i=`${e}:${JSON.stringify(t||{})}`;if(!this.domainLoggers.has(i)){let e=this.globalLogger;t&&(e=e.with(t)),this.domainLoggers.set(i,e)}return this.domainLoggers.get(i)}getComponentLogger(e,t){return this.getDomainLogger(e,{component:e,...t})}}}}),init_email=__esm({"internal/domain/identity/value-object/email.ts"(){Email=class e{constructor(e){__publicField(this,"value"),this.value=e}static create(t){if(!e.isValid(t))throw new Error(`Invalid email address: ${t}`);return new e(t)}static isValid(e){return!(!e||"string"!=typeof e)&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}getValue(){return this.value}getDomain(){return this.value.split("@")[1]}getLocalPart(){return this.value.split("@")[0]}equals(e){return this.value.toLowerCase()===e.value.toLowerCase()}toString(){return this.value}toJSON(){return this.value}}}}),init_token=__esm({"internal/domain/identity/value-object/token.ts"(){Token=class e{constructor(e,t){__publicField(this,"value"),__publicField(this,"expiresAt"),this.value=e,this.expiresAt=t}static create(t,i){if(!t||"string"!=typeof t||0===t.trim().length)throw new Error("Token value cannot be empty");return new e(t,i)}static fromJSON(t){return e.create(t.token,t.expiresAt)}getValue(){return this.value}getExpiresAt(){return this.expiresAt}isExpired(){return!!this.expiresAt&&Date.now()>this.expiresAt}isValid(){return!this.isExpired()}getRemainingTime(){if(!this.expiresAt)return null;const e=this.expiresAt-Date.now();return e>0?e:0}equals(e){return this.value===e.value}toString(){return this.value}toJSON(){const e={token:this.value};return void 0!==this.expiresAt&&(e.expiresAt=this.expiresAt),e}}}}),init_server_config=__esm({"internal/domain/identity/value-object/server-config.ts"(){ServerConfig=class e{constructor(e,t){__publicField(this,"apiUrl"),__publicField(this,"websiteUrl"),this.apiUrl=e,this.websiteUrl=t}static create(t,i){if(!t||"string"!=typeof t||0===t.trim().length)throw new Error("API URL cannot be empty");if(!e.isValidUrl(t))throw new Error(`Invalid API URL: ${t}`);if(i&&!e.isValidUrl(i))throw new Error(`Invalid website URL: ${i}`);return new e(t,i)}static fromJSON(t){return e.create(t.apiUrl,t.websiteUrl)}static createDefault(){return e.create("https://app.mdfriday.com","https://mdfriday.com")}static isValidUrl(e){try{return new URL(e),!0}catch{return!1}}getApiUrl(){return this.apiUrl}getWebsiteUrl(){return this.websiteUrl}withApiUrl(t){return e.create(t,this.websiteUrl)}withWebsiteUrl(t){return e.create(this.apiUrl,t)}equals(e){return this.apiUrl===e.apiUrl&&this.websiteUrl===e.websiteUrl}toJSON(){const e={apiUrl:this.apiUrl};return void 0!==this.websiteUrl&&(e.websiteUrl=this.websiteUrl),e}}}}),init_license=__esm({"internal/domain/identity/value-object/license.ts"(){License=class e{constructor(e,t,i,s,r,a=!1,n=!1){__publicField(this,"key"),__publicField(this,"plan"),__publicField(this,"expiresAt"),__publicField(this,"features"),__publicField(this,"activatedAt"),__publicField(this,"activated"),__publicField(this,"firstTime"),this.key=e,this.plan=t,this.expiresAt=i,this.features=s,this.activatedAt=r,this.activated=a,this.firstTime=n}static create(t,i,s,r,a,n,o){if(!e.isValidFormat(t))throw new Error(`Invalid license key format: ${t}`);return new e(t.toUpperCase(),i,s,r,a||Date.now(),n||!1,o||!1)}static fromJSON(t){return e.create(t.key,t.plan,t.expiresAt,t.features,t.activatedAt,t.activated,t.firstTime)}static isValidFormat(e){return/^MDF-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/i.test(e)}isExpired(){return Date.now()>this.expiresAt}isValid(){return!this.isExpired()}getDaysRemaining(){const e=this.expiresAt-Date.now();return Math.max(0,Math.ceil(e/864e5))}getEmail(){return`${this.key.replace(/^MDF-/i,"").toLowerCase()}@mdfriday.com`}getPassword(){const e=this.key.replace(/^MDF-/i,"").toLowerCase();return"undefined"!=typeof btoa?btoa(e):"undefined"!=typeof Buffer?Buffer.from(e).toString("base64"):this.manualBase64Encode(e)}manualBase64Encode(e){const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";let i="",s=0;for(;s<e.length;){const r=e.charCodeAt(s++)<<16|(s<e.length?e.charCodeAt(s++):0)<<8|(s<e.length?e.charCodeAt(s++):0);i+=t.charAt(r>>18&63),i+=t.charAt(r>>12&63),i+=s-1<e.length?t.charAt(r>>6&63):"=",i+=s<e.length?t.charAt(63&r):"="}return i}getKey(){return this.key}getMaskedKey(){const e=this.key.split("-");return 4===e.length?`MDF-••••-••••-${e[3]}`:this.key.slice(0,-4).replace(/./g,"•")+this.key.slice(-4)}getPlan(){return this.plan}getFormattedPlan(){return this.plan.charAt(0).toUpperCase()+this.plan.slice(1).toLowerCase()}getExpiresAt(){return this.expiresAt}getFormattedExpiresAt(){return new Date(this.expiresAt).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}getFeatures(){return{...this.features}}getActivatedAt(){return this.activatedAt}isActivated(){return this.activated}isFirstTime(){return this.firstTime}isTrial(){return"free"===this.plan}equals(e){return this.key===e.key}toJSON(){return{key:this.key,plan:this.plan,expiresAt:this.expiresAt,features:{...this.features},activatedAt:this.activatedAt,activated:this.activated,firstTime:this.firstTime}}toStorageFormat(){return{key:this.key,maskedKey:this.getMaskedKey(),plan:this.getFormattedPlan(),expiresAt:this.expiresAt,features:{...this.features},activatedAt:this.activatedAt,activated:this.activated,firstTime:this.firstTime,isValid:this.isValid(),daysRemaining:this.getDaysRemaining()}}}}}),init_sync_config=__esm({"internal/domain/identity/value-object/sync-config.ts"(){SyncConfig=class e{constructor(e){__publicField(this,"dbEndpoint"),__publicField(this,"dbName"),__publicField(this,"email"),__publicField(this,"dbPassword"),__publicField(this,"userDir"),__publicField(this,"status"),this.dbEndpoint=e.dbEndpoint,this.dbName=e.dbName,this.email=e.email,this.dbPassword=e.dbPassword,this.userDir=e.userDir,this.status=e.status||"active"}static create(t){if(!(t.dbEndpoint&&t.dbName&&t.email&&t.dbPassword))throw new Error("Missing required sync configuration fields");return new e(t)}static fromJSON(t){return e.create(t)}getDbEndpoint(){return this.dbEndpoint}getDbName(){return this.dbName}getEmail(){return this.email}getDbPassword(){return this.dbPassword}getUserDir(){return this.userDir}getStatus(){return this.status}isActive(){return"active"===this.status}getCouchDbUri(){return this.dbEndpoint.replace(`/${this.dbName}`,"")}toJSON(){return{dbEndpoint:this.dbEndpoint,dbName:this.dbName,email:this.email,dbPassword:this.dbPassword,userDir:this.userDir,status:this.status}}toObsidianLiveSyncFormat(){return{couchDB_URI:this.getCouchDbUri(),couchDB_DBNAME:this.dbName,couchDB_USER:this.email,couchDB_PASSWORD:this.dbPassword,encrypt:!0,syncOnStart:!0,syncOnSave:!0,liveSync:!0}}equals(e){return this.dbEndpoint===e.dbEndpoint&&this.dbName===e.dbName&&this.email===e.email}}}}),init_device=__esm({"internal/domain/identity/value-object/device.ts"(){Device=class e{constructor(e,t,i){__publicField(this,"id"),__publicField(this,"name"),__publicField(this,"type"),this.id=e,this.name=t,this.type=i}static create(t,i,s){if(!t||0===t.trim().length)throw new Error("Device ID cannot be empty");if(!i||0===i.trim().length)throw new Error("Device name cannot be empty");return new e(t,i,s)}static async createFromEnvironment(){const t=await e.generateFingerprint(),i=e.getDeviceName(),s=e.getDeviceType();return e.create(t,i,s)}static async generateFingerprint(){const e=[],t=globalThis,i=t.screen;i&&(e.push(`${i.width}x${i.height}`),e.push(`${i.colorDepth}`),e.push(`${i.pixelDepth||0}`));const s=t.navigator;s&&(e.push(s.language||""),e.push(s.platform||""),e.push(String(s.hardwareConcurrency||0)),e.push(String(s.maxTouchPoints||0)));const r=t.process;r&&r.versions&&(e.push(r.platform),e.push(r.arch),e.push(r.version));try{"undefined"!=typeof Intl&&e.push(Intl.DateTimeFormat().resolvedOptions().timeZone||"")}catch{e.push("")}if(s){const t=(s.userAgent||"").split(" ").slice(0,3).join(" ");e.push(t)}const a=e.join("|"),n=(new TextEncoder).encode(a),o=t.crypto;if(o&&o.subtle)try{const e=await o.subtle.digest("SHA-256",n);return Array.from(new Uint8Array(e)).map(e=>e.toString(16).padStart(2,"0")).join("")}catch{}let c=0;for(let e=0;e<a.length;e++)c=(c<<5)-c+a.charCodeAt(e),c&=c;return Math.abs(c).toString(16).padStart(8,"0")}static getDeviceName(){const e=globalThis,t=e.process;if(t&&t.versions){const e=t.platform;let i="Unknown OS";switch(e){case"darwin":i="macOS";break;case"win32":i="Windows";break;case"linux":i="Linux";break;default:i=e}return`Node.js on ${i}`}const i=e.navigator;if(!i)return"Unknown Device";const s=i.userAgent||"";let r="Unknown OS";s.includes("Mac")?r="macOS":s.includes("Windows")?r="Windows":s.includes("Linux")?r="Linux":s.includes("iPhone")||s.includes("iPad")?r="iOS":s.includes("Android")&&(r="Android");let a="Browser";return s.includes("Obsidian")?a="Obsidian":s.includes("Electron")&&(a="Electron"),`${a} on ${r}`}static getDeviceType(){const e=globalThis,t=e.process;if(t&&t.versions)return"desktop";const i=e.navigator;if(!i)return"desktop";const s=i.userAgent||"";return s.includes("Mobile")||s.includes("Android")||s.includes("iPhone")?"mobile":s.includes("Tablet")||s.includes("iPad")?"tablet":"desktop"}getId(){return this.id}getName(){return this.name}getType(){return this.type}equals(e){return this.id===e.id}toJSON(){return{id:this.id,name:this.name,type:this.type}}}}}),init_user=__esm({"internal/domain/identity/entity/user.ts"(){User=class{constructor(e,t,i,s=null,r=null){__publicField(this,"email"),__publicField(this,"token"),__publicField(this,"serverConfig"),__publicField(this,"license"),__publicField(this,"syncConfig"),this.email=e,this.token=t,this.serverConfig=i,this.license=s,this.syncConfig=r}getEmail(){return this.email}getToken(){return this.token}getServerConfig(){return this.serverConfig}getLicense(){return this.license}getSyncConfig(){return this.syncConfig}setToken(e){this.token=e}clearToken(){this.token=null}updateServerConfig(e){this.serverConfig=e}setLicense(e){this.license=e}clearLicense(){this.license=null}setSyncConfig(e){this.syncConfig=e}clearSyncConfig(){this.syncConfig=null}isAuthenticated(){return!!this.token&&this.token.isValid()}isTokenExpired(){return!this.token||this.token.isExpired()}hasValidLicense(){return!!this.license&&this.license.isValid()}isTrialAccount(){return!!this.license&&this.license.isTrial()}getStatus(){const e={isAuthenticated:this.isAuthenticated(),email:this.email.getValue(),serverUrl:this.serverConfig.getApiUrl(),tokenExpired:this.isTokenExpired(),hasToken:null!==this.token,hasLicense:null!==this.license,license:this.license?.getKey(),licenseValid:this.hasValidLicense(),isTrial:this.isTrialAccount(),licensePlan:this.license?.getPlan(),licenseExpires:this.license?.getFormattedExpiresAt(),licenseDaysRemaining:this.license?.getDaysRemaining(),hasSyncConfig:null!==this.syncConfig};return this.syncConfig&&(e.syncConfig={dbEndpoint:this.syncConfig.getDbEndpoint(),dbName:this.syncConfig.getDbName(),email:this.syncConfig.getEmail(),userDir:this.syncConfig.getUserDir(),status:this.syncConfig.getStatus(),isActive:this.syncConfig.isActive()}),e}toJSON(){return{email:this.email.toJSON(),token:this.token?.toJSON()||null,serverConfig:this.serverConfig.toJSON(),license:this.license?.toJSON()||null,syncConfig:this.syncConfig?.toJSON()||null}}}}}),init_user_factory=__esm({"internal/domain/identity/factory/user-factory.ts"(){init_user(),init_email(),init_token(),init_server_config(),init_license(),init_sync_config(),init_device(),init_browser_manager(),log4=getDomainLogger("user-factory",{component:"domain"}),UserFactory=class{constructor(e){__publicField(this,"httpClient"),__publicField(this,"storageProvider"),this.httpClient=e.httpClient,this.storageProvider=e.storageProvider}createAnonymous(e){const t=e||ServerConfig.createDefault(),i=Email.create("anonymous@localhost.local");return new User(i,null,t)}async load(){try{const e=await this.storageProvider.loadUserData();if(!e||!e.token)return log4.debug("No user data found in storage"),null;const t=e.serverConfig||ServerConfig.createDefault(),i=e.email?Email.create(e.email):Email.create("anonymous@localhost.local"),s=new User(i,e.token,t);if(e.license&&s.setLicense(e.license),e.syncConfig){const t=SyncConfig.fromJSON(e.syncConfig);s.setSyncConfig(t)}return log4.debug("User loaded from storage",{email:i.getValue(),hasToken:!!e.token,hasLicense:!!e.license,hasSyncConfig:!!e.syncConfig}),s}catch(e){return log4.error("Failed to load user from storage",e),null}}async save(e){try{const t=await this.storageProvider.loadUserData(),i=e.getToken(),s=e.getLicense(),r=e.getSyncConfig(),a=e.getServerConfig(),n=e.getEmail().getValue(),o={...t||{},...i?{token:i}:{},...s?{license:s}:{},...r?{syncConfig:r}:{},...a?{serverConfig:a}:{},email:n};!s&&t?.license&&(o.license=t.license,log4.debug("Preserved existing license data during save")),!r&&t?.syncConfig&&(o.syncConfig=t.syncConfig,log4.debug("Preserved existing syncConfig data during save")),await this.storageProvider.saveUserData(o),log4.debug("User saved to storage (merged)",{email:n,hasToken:!!o.token,hasLicense:!!o.license,hasSyncConfig:!!o.syncConfig,preservedLicense:!s&&!!t?.license,preservedSyncConfig:!r&&!!t?.syncConfig})}catch(e){throw log4.error("Failed to save user to storage",e),e}}async loadServerConfig(){try{const e=await this.storageProvider.loadUserData();return e?.serverConfig||null}catch(e){return log4.debug("No server config found in storage"),null}}async login(e,t,i){const s=Email.create(e),r=i||ServerConfig.createDefault();log4.info("Attempting login",{email:e});try{const i=`${r.getApiUrl()}/api/login`;log4.info(`Sending login request to: ${i}`),log4.debug(`Login credentials: email=${e}, password=***`);const a=await this.httpClient.postForm(i,{email:e,password:t});if(log4.info(`Login response status: ${a.status}`),log4.debug("Login response data:",a.data),201!==a.status){const e=await a.text();throw log4.error(`Login failed with status ${a.status}: ${e}`),new Error("Invalid credentials")}log4.debug("Response structure:",JSON.stringify(a.data,null,2));const n=a.data.data[0];if(!n)throw log4.error("No token in response data:",a.data),new Error("No token received from server");log4.info(`Token received: ${n.substring(0,20)}...`);const o=Token.create(n),c=new User(s,o,r);return await this.save(c),log4.info("Login successful",{email:e}),c}catch(e){throw log4.error("Login failed",e),new Error(`Login failed: ${e.message}`)}}async register(e,t,i){const s=Email.create(e),r=i||ServerConfig.createDefault();log4.info("Attempting registration",{email:e});try{const i=await this.httpClient.postForm(`${r.getApiUrl()}/api/user`,{email:e,password:t});if(201!==i.status)throw new Error("Registration failed");const a=i.data.data[0];if(!a)throw new Error("No token received from server");const n=Token.create(a),o=new User(s,n,r);return await this.save(o),log4.info("Registration successful",{email:e}),o}catch(e){throw log4.error("Registration failed",e),new Error(`Registration failed: ${e.message}`)}}async logout(){try{await this.storageProvider.clearUserData(),log4.info("Logout successful")}catch(e){throw log4.error("Logout failed",e),new Error(`Logout failed: ${e.message}`)}}async updateServerConfig(e,t){try{let i=e.getServerConfig();t.apiUrl&&(i=i.withApiUrl(t.apiUrl)),void 0!==t.websiteUrl&&(i=i.withWebsiteUrl(t.websiteUrl)),e.updateServerConfig(i),await this.save(e),log4.info("Server config updated")}catch(e){throw log4.error("Failed to update server config",e),new Error(`Failed to update server config: ${e.message}`)}}async requestTrialLicense(e,t){const i=t||ServerConfig.createDefault();Email.create(e),log4.info("Requesting trial license",{email:e});try{const t=await this.httpClient.postMultipart(`${i.getApiUrl()}/api/license/trial`,{email:e});if(200!==t.status&&201!==t.status)throw new Error("Trial license request failed");const s=t.data;if(s&&s.data&&s.data.length>0){const e=s.data[0];return log4.info("Trial license granted",{email:e.email,licenseKey:e.license_key}),e}throw new Error("Invalid trial response format")}catch(e){throw log4.error("Failed to request trial license",e),new Error(`Trial license request failed: ${e.message}`)}}async loginWithLicense(e,t){if(!License.isValidFormat(e))throw new Error(`Invalid license key format: ${e}`);const i=License.create(e,"free",Date.now()+864e5,{},Date.now()),s=i.getEmail(),r=i.getPassword();log4.info("Logging in with license key",{licenseKey:e,email:s});const a=await this.login(s,r,t);return a._pendingLicenseKey=e,a}async activateLicense(e,t,i){if(!License.isValidFormat(t))throw new Error(`Invalid license key format: ${t}`);const s=i||await Device.createFromEnvironment();log4.info("Activating license",{licenseKey:t,deviceId:s.getId()});try{const i=e.getToken();if(!i)throw new Error("User must be logged in to activate license");const r=await this.httpClient.postMultipart(`${e.getServerConfig().getApiUrl()}/api/license/activate`,{license_key:t,device_id:s.getId(),device_name:s.getName(),device_type:s.getType()},{Authorization:`Bearer ${i.getValue()}`});if(200!==r.status&&201!==r.status)throw new Error("License activation failed");const a=r.data.data?.[0]||r.data;if(!a.success)throw new Error("License activation unsuccessful");const n={maxDevices:a.features.max_devices,maxIps:a.features.max_ips,syncEnabled:a.features.sync_enabled,syncQuota:a.features.sync_quota,publishEnabled:a.features.publish_enabled,maxSites:a.features.max_sites,maxStorage:a.features.max_storage,customDomain:a.features.custom_domain,customSubDomain:a.features.custom_sub_domain,validityDays:a.features.validity_days},o=License.create(a.license_key,a.plan,a.expires_at,n,Date.now(),a.activated,a.first_time);if(e.setLicense(o),a.sync&&a.features.sync_enabled){const t=SyncConfig.create({dbEndpoint:a.sync.db_endpoint,dbName:a.sync.db_name,email:a.sync.email,dbPassword:a.sync.db_password,userDir:a.user.user_dir,status:a.sync.status});e.setSyncConfig(t),log4.info("Sync configuration saved",{dbName:t.getDbName(),email:t.getEmail(),userDir:t.getUserDir(),status:t.getStatus(),isActive:t.isActive()})}return await this.save(e),log4.info("License activated successfully",{licenseKey:a.license_key,plan:o.getPlan(),expires:o.getFormattedExpiresAt(),activated:a.activated,firstTime:a.first_time,syncEnabled:a.features.sync_enabled,hasSyncConfig:null!==e.getSyncConfig()}),e}catch(e){throw log4.error("Failed to activate license",e),new Error(`License activation failed: ${e.message}`)}}async requestAndActivateTrial(e,t){log4.info("Starting trial flow",{email:e});try{const i=await this.requestTrialLicense(e,t),s=await this.loginWithLicense(i.license_key,t);return await this.activateLicense(s,i.license_key),log4.info("Trial flow completed successfully",{email:e,licenseKey:i.license_key}),s}catch(e){throw log4.error("Trial flow failed",e),new Error(`Trial flow failed: ${e.message}`)}}async refreshTokenIfNeeded(e){const t=e.getToken(),i=e.getLicense();if(!t)return log4.debug("No token to refresh"),e;if(t.isValid()&&!t.isExpired())return log4.debug("Token is still valid, no refresh needed"),e;if(log4.info("Token expired or expiring soon, attempting auto-refresh"),i)try{const t=i.getKey(),s=e.getServerConfig();log4.info("Refreshing token using license",{licenseKey:t});const r=await this.loginWithLicense(t,s);return r.setLicense(i),await this.save(r),log4.info("Token refreshed successfully using license"),r}catch(e){throw log4.error("Failed to refresh token with license",e),new Error(`Failed to refresh token: ${e.message}`)}throw log4.warn("Token expired but no license available for auto-refresh"),new Error("Token expired and cannot be auto-refreshed (no license available)")}async requestWithAutoRefresh(e,t){const i=e.getToken();if(!i)throw new Error("User is not authenticated");try{return await t(i.getValue())}catch(i){const s=i?.message||i?.toString?.()||String(i);if(s.includes("401")||s.includes("Unauthorized")||i?.status&&401===i.status){log4.info("Received 401 error, attempting token refresh");try{const i=(await this.refreshTokenIfNeeded(e)).getToken();if(!i)throw new Error("Failed to refresh token - no token returned");return log4.info("Token refreshed, retrying request"),await t(i.getValue())}catch(e){throw log4.error("Failed to refresh token and retry request",e),new Error(`Request failed with 401, and token refresh failed: ${e.message}`)}}throw i}}async getLicenseUsage(e){const t=e.getLicense();if(!t)throw new Error("No license found for user");const i=t.getKey(),s=e.getServerConfig();return log4.info("Getting license usage",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=Date.now(),r=`${s.getApiUrl()}/api/license/usage?key=${i}&_t=${t}`,a=await this.httpClient.get(r,{Authorization:`Bearer ${e}`,"Cache-Control":"no-cache",Pragma:"no-cache"});if(200!==a.status){const e=await a.text();throw log4.error("License usage fetch failed",{status:a.status,text:e}),new Error(`License usage fetch failed: ${a.status}`)}const n=a.data;if(n&&n.data&&n.data.length>0)return n.data[0];throw new Error("Invalid usage response format")})}async getLicenseInfo(e,t){let i=t;if(!i){const t=e.getLicense();if(!t)throw new Error("No license found for user and no license key provided");i=t.getKey()}const s=e.getServerConfig();return log4.info("Getting license info",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=Date.now(),r=`${s.getApiUrl()}/api/license/info?key=${i}&_t=${t}`,a=await this.httpClient.get(r,{Authorization:`Bearer ${e}`,"Cache-Control":"no-cache",Pragma:"no-cache"});if(200!==a.status){const e=await a.text();throw log4.error("License info fetch failed",{status:a.status,text:e}),new Error(`License info fetch failed: ${a.status}`)}const n=a.data;if(n&&n.data&&n.data.length>0)return n.data[0];throw new Error("Invalid license info response format")})}async resetUsage(e){const t=e.getLicense();if(!t)throw new Error("No license found for user");const i=t.getKey(),s=e.getServerConfig();return log4.info("Resetting license usage",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=`${s.getApiUrl()}/api/license/usage/reset?key=${i}`,r=await this.httpClient.post(t,{},{Authorization:`Bearer ${e}`});if(200!==r.status&&201!==r.status){const e=await r.text();throw log4.error("License usage reset failed",{status:r.status,text:e}),new Error(`Reset failed: ${r.status}`)}return{success:!0}})}async getDomains(e){const t=e.getLicense();if(!t)throw new Error("No license found for user");const i=t.getKey(),s=e.getServerConfig();return log4.info("Getting domains",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=`${s.getApiUrl()}/api/license/domains?key=${i}`,r=await this.httpClient.get(t,{Authorization:`Bearer ${e}`});if(200!==r.status){const e=await r.text();return log4.error("Get domains failed",{status:r.status,text:e}),null}const a=r.data;return a&&a.data&&a.data.length>0?a.data[0]:null})}async checkSubdomainAvailability(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Checking subdomain availability",{licenseKey:s,subdomain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/subdomain/check`,a=await this.httpClient.postMultipart(i,{license_key:s,subdomain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Check subdomain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async updateSubdomain(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Updating subdomain",{licenseKey:s,newSubdomain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/subdomain/update`,a=await this.httpClient.postMultipart(i,{license_key:s,new_subdomain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Update subdomain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async checkCustomDomain(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Checking custom domain",{licenseKey:s,domain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/domain/check`,a=await this.httpClient.postMultipart(i,{license_key:s,domain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Check custom domain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async addCustomDomain(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Adding custom domain",{licenseKey:s,domain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/domain/add`,a=await this.httpClient.postMultipart(i,{license_key:s,domain:t},{Authorization:`Bearer ${e}`});if(200!==a.status&&201!==a.status){const e=await a.text();return log4.error("Add custom domain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async checkCustomDomainHttpsStatus(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Checking HTTPS status",{licenseKey:s,domain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/domain/https-status`,a=await this.httpClient.postMultipart(i,{license_key:s,domain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Check HTTPS status failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}}}}),init_type=__esm({"internal/domain/identity/type.ts"(){}}),identity_exports={};__export(identity_exports,{Device:()=>Device,Email:()=>Email,License:()=>License,ServerConfig:()=>ServerConfig,SyncConfig:()=>SyncConfig,Token:()=>Token,User:()=>User,UserFactory:()=>UserFactory});var ProjectMetadata,init_identity=__esm({"internal/domain/identity/index.ts"(){init_email(),init_token(),init_server_config(),init_license(),init_sync_config(),init_device(),init_user(),init_user_factory(),init_type()}}),project_metadata_exports={};__export(project_metadata_exports,{ProjectMetadata:()=>ProjectMetadata});var mod,init_project_metadata=__esm({"internal/domain/workspace/value-object/project-metadata.ts"(){ProjectMetadata=class e{constructor(e){__publicField(this,"id"),__publicField(this,"name"),__publicField(this,"workspaceId"),__publicField(this,"createdAt"),__publicField(this,"updatedAt"),__publicField(this,"buildHistory"),__publicField(this,"previews"),__publicField(this,"contentLinks"),__publicField(this,"staticLink"),__publicField(this,"fileLink"),__publicField(this,"baseURLStructure"),this.id=e.id,this.name=e.name,this.workspaceId=e.workspaceId||"",this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this.buildHistory=e.buildHistory||[],this.previews=e.previews||{},this.contentLinks=e.contentLinks||[],this.staticLink=e.staticLink||null,this.fileLink=e.fileLink||null,this.baseURLStructure=e.baseURLStructure||null}static create(t){if(!t.id||!t.name)throw new Error("Project ID and name are required");return new e(t)}update(t){return new e({...this,...t,updatedAt:Date.now()})}toJSON(){const e={id:this.id,name:this.name,createdAt:this.createdAt,updatedAt:this.updatedAt};return this.workspaceId&&(e.workspaceId=this.workspaceId),this.buildHistory&&this.buildHistory.length>0&&(e.buildHistory=this.buildHistory),this.previews&&Object.keys(this.previews).length>0&&(e.previews=this.previews),this.contentLinks&&this.contentLinks.length>0&&(e.contentLinks=this.contentLinks),this.staticLink&&(e.staticLink=this.staticLink),this.fileLink&&(e.fileLink=this.fileLink),this.baseURLStructure&&(e.baseURLStructure=this.baseURLStructure),e}}}}),mobile_exports={};__export(mobile_exports,{createObsidianAuthService:()=>createObsidianAuthService,createObsidianGlobalConfigService:()=>createObsidianGlobalConfigService,createObsidianIdentityService:()=>createObsidianIdentityService,createObsidianLicenseService:()=>createObsidianLicenseService,createObsidianWorkspaceAppService:()=>createObsidianWorkspaceAppService,createObsidianWorkspaceService:()=>createObsidianWorkspaceService}),module.exports=(mod=mobile_exports,((e,t,i,s)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let i of __getOwnPropNames(t))__hasOwnProp.call(e,i)||void 0===i||__defProp(e,i,{get:()=>t[i],enumerable:!(s=__getOwnPropDesc(t,i))||s.enumerable});return e})(__defProp({},"__esModule",{value:!0}),mod));var ObsidianAuthService=class{constructor(e,t){this.httpClient=e,this.identityAdapter=t}async getStatus(e){try{const t=await this.identityAdapter.getIdentityService(e,this.httpClient),i=t.getStatus(),s={isAuthenticated:i.isAuthenticated,serverUrl:i.serverUrl,hasSyncConfig:i.hasSyncConfig,...i.license?{license:i.license}:{},...i.email?{email:i.email}:{}};if(i.isAuthenticated){const e=t.getToken();e&&(s.token=e)}return i.syncConfig&&(s.syncConfig={dbEndpoint:i.syncConfig.dbEndpoint,dbName:i.syncConfig.dbName,email:i.syncConfig.email,userDir:i.syncConfig.userDir,status:i.syncConfig.status,isActive:i.syncConfig.isActive}),{success:!0,message:i.isAuthenticated?`Authenticated as ${i.email}`:"Not authenticated",data:s}}catch(e){const t=e.message;return t.includes("No workspace found")?{success:!1,message:"No workspace found. Please initialize workspace first.",error:t}:{success:!1,message:`Failed to get status: ${t}`,error:t}}}async getConfig(e){try{const t=(await this.identityAdapter.getIdentityService(e,this.httpClient)).getServerConfig(),i=t.getWebsiteUrl(),s={apiUrl:t.getApiUrl()};return i&&(s.websiteUrl=i),{success:!0,message:"Server configuration retrieved",data:s}}catch(e){const t=e.message;return t.includes("No workspace found")?{success:!1,message:"No workspace found. Please initialize workspace first.",error:t}:{success:!1,message:`Failed to get config: ${t}`,error:t}}}async updateConfig(e,t){try{const i={};t.apiUrl&&(i.apiUrl=t.apiUrl),t.websiteUrl&&(i.websiteUrl=t.websiteUrl);const s=await this.identityAdapter.getIdentityService(e,this.httpClient);await s.updateServerConfig(i);const r=s.getServerConfig(),a=r.getWebsiteUrl(),n={apiUrl:r.getApiUrl()};return a&&(n.websiteUrl=a),{success:!0,message:"Server configuration updated",data:n}}catch(e){const t=e.message;return t.includes("No workspace found")?{success:!1,message:"No workspace found. Please initialize workspace first.",error:t}:{success:!1,message:`Failed to update config: ${t}`,error:t}}}};init_browser_manager();var log=getDomainLogger("obsidian-license",{component:"interface"}),ObsidianLicenseService=class{constructor(e,t){this.httpClient=e,this.identityAdapter=t}async requestTrial(e,t){try{if(!t)return{success:!1,error:"Email is required"};log.info("Requesting trial license (without activation)",{email:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.requestTrial(t);return{success:!0,message:"Trial license requested successfully",data:{email:s.email,licenseKey:s.license_key,password:s.password,validityDays:s.validity_days}}}catch(e){return log.error("Trial license request failed",e),{success:!1,error:e.message}}}async requestAndActivateTrial(e,t){try{if(!t)return{success:!1,error:"Email is required"};log.info("Requesting and activating trial license",{email:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=(await i.requestAndActivateTrial(t)).getLicense();return s?{success:!0,message:"Trial license activated successfully",data:this.buildLicenseInfo(s)}:{success:!1,error:"Trial license request succeeded but license not found"}}catch(e){return log.error("Trial license request and activation failed",e),{success:!1,error:e.message}}}async loginWithLicense(e,t){try{if(!t)return{success:!1,error:"License key is required"};log.info("Logging in with license key",{licenseKey:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.loginWithLicense(t);return log.info("Login successful",{email:s.getEmail().getValue(),hasToken:!!s.getToken()}),{success:!0,message:"Logged in successfully. Token saved.",data:{}}}catch(e){return log.error("License login failed",e),{success:!1,error:e.message}}}async activateLicense(e,t){try{if(!t)return{success:!1,error:"License key is required"};log.info("Activating license",{licenseKey:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.activateLicense(t),r=s.getLicense(),a=s.getSyncConfig();if(!r)return{success:!1,error:"License activation succeeded but license not found"};const n=this.buildLicenseInfo(r);return n.user={email:s.getEmail().getValue(),userDir:a?.getUserDir()||""},n.activation={activated:r.isActivated(),firstTime:r.isFirstTime()},a&&r.getFeatures().syncEnabled&&(n.sync={enabled:!0,status:a.getStatus(),dbEndpoint:a.getDbEndpoint(),dbName:a.getDbName(),email:a.getEmail(),dbPassword:a.getDbPassword(),userDir:a.getUserDir(),liveSyncConfig:a.toObsidianLiveSyncFormat()},log.info("Sync configuration included in activation response",{dbName:a.getDbName(),email:a.getEmail(),status:a.getStatus()})),{success:!0,message:"License activated successfully",data:n}}catch(e){return log.error("License activation failed",e),{success:!1,error:e.message}}}async getLicenseInfo(e){try{const t=await this.identityAdapter.getIdentityService(e,this.httpClient),i=t.getLicense();if(!i)return{success:!0,message:"No active license"};const s=this.buildLicenseInfo(i),r=t.getCurrentUser();if(r){const e=r.getSyncConfig();s.user={email:r.getEmail().getValue(),userDir:e?.getUserDir()||""}}return{success:!0,data:s}}catch(e){return log.error("Failed to get license info",e),{success:!1,error:e.message}}}async getLicenseUsage(e){try{const t=await this.identityAdapter.getIdentityService(e,this.httpClient),i=await t.getLicenseUsage();return i?{success:!0,data:{licenseKey:i.license_key,plan:i.plan,devices:{count:i.devices.count,max:i.features.max_devices,list:i.devices.devices.map(e=>({id:e.id,name:e.device_name,type:e.device_type,status:e.status,lastSeenAt:e.last_seen_at}))},ips:{count:i.ips.count,max:i.features.max_ips,list:i.ips.ips.map(e=>({ip:e.ip_address,city:e.city,region:e.region,country:e.country,status:e.status,lastSeenAt:e.last_seen_at}))},disk:{syncUsage:Number(i.disks.sync_disk_usage)||0,publishUsage:Number(i.disks.publish_disk_usage)||0,totalUsage:Number(i.disks.total_disk_usage)||0,maxStorage:i.features.max_storage,unit:i.disks.unit}}}:{success:!1,error:"Failed to get license usage information"}}catch(e){return log.error("Failed to get license usage",e),{success:!1,error:e.message}}}async resetUsage(e,t){try{if(!t)return{success:!1,error:"This will delete all sync and publish data! Set force=true to confirm."};const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.resetUsage();return s.success?{success:!0,message:"License usage data has been reset successfully",data:s}:{success:!1,error:s.message||"Unknown error"}}catch(e){return log.error("Failed to reset license usage",e),{success:!1,error:e.message}}}async hasActiveLicense(e){try{const t=await this.getLicenseInfo(e);return t.success&&void 0!==t.data&&!t.data.isExpired}catch{return!1}}buildLicenseInfo(e){const t=e.getFeatures();return{key:e.getKey(),plan:e.getFormattedPlan(),isExpired:e.isExpired(),expires:e.getFormattedExpiresAt(),expiresAt:e.getExpiresAt(),daysRemaining:e.getDaysRemaining(),isTrial:e.isTrial(),features:{maxDevices:t.maxDevices,maxIps:t.maxIps,syncEnabled:t.syncEnabled,syncQuota:t.syncQuota,publishEnabled:t.publishEnabled,maxSites:t.maxSites,maxStorage:t.maxStorage,customDomain:t.customDomain,customSubDomain:t.customSubDomain}}}};init_browser_manager();var log2=getDomainLogger("obsidian-workspace",{component:"interface"}),ObsidianWorkspaceService=class{constructor(e){this.workspaceAdapter=e}buildWorkspaceInfo(e){const t=e.getInfo(),i=e.getProjects();return{id:t.id,name:t.name,path:t.path,createdAt:t.createdAt.toISOString(),modulesDir:t.modulesDir,projectsDir:t.projectsDir,projectCount:t.projectCount,projects:i.map(e=>{const t=e.getMetadata(),i=t.buildHistory||[],s=i.length>0?new Date(i[i.length-1].timestamp).toISOString():void 0,r={id:t.id,name:t.name,path:e.getPath(),createdAt:new Date(t.createdAt).toISOString()};return s&&(r.lastBuild=s),r})}}async initWorkspace(e,t={}){try{log2.info("Initializing workspace from Obsidian",{workspacePath:e,options:t});const i=this.workspaceAdapter.getWorkspaceAppService(),s={};t.name&&(s.name=t.name),t.modulesDir&&(s.modulesDir=t.modulesDir),t.projectsDir&&(s.projectsDir=t.projectsDir);const r=await i.createWorkspace(e,s),a=this.buildWorkspaceInfo(r);return log2.info("Workspace initialized successfully",{workspaceId:a.id,name:a.name,projectCount:a.projects.length}),{success:!0,message:`Workspace initialized: ${a.name}`,data:a}}catch(e){return log2.error("Failed to initialize workspace",e),{success:!1,message:"Failed to initialize workspace",error:e.message}}}async getWorkspaceInfo(e){try{log2.info("Getting workspace info from Obsidian",{workspacePath:e});const t=this.workspaceAdapter.getWorkspaceAppService(),i=await t.loadWorkspace(e),s=this.buildWorkspaceInfo(i);return log2.info("Workspace info retrieved",{workspaceId:s.id,name:s.name,projectCount:s.projects.length}),{success:!0,data:s}}catch(e){return log2.error("Failed to get workspace info",e),{success:!1,message:"Failed to get workspace info",error:e.message}}}async workspaceExists(e){try{log2.debug("Checking workspace existence",{workspacePath:e});const t=this.workspaceAdapter.getFileSystemRepository(),i=this.workspaceAdapter.getWorkspaceFactory(),s=await t.resolvePath(e);return{success:!0,data:await i.isWorkspace(s)}}catch(e){return log2.error("Failed to check workspace existence",e),{success:!1,error:e.message,data:!1}}}};init_browser_manager();var log3=getDomainLogger("obsidian-config",{component:"interface"}),ObsidianGlobalConfigService=class{constructor(e){this.workspaceAdapter=e}async get(e,t){try{log3.info("Getting global config",{workspacePath:e,key:t});const i=this.workspaceAdapter.getWorkspaceAppService(),s=await i.loadWorkspace(e),r=await s.getConfig(t);return void 0===r?{success:!1,error:`Configuration key not found: ${t}`}:{success:!0,data:{key:t,value:r}}}catch(e){return log3.error("Failed to get global config",e),{success:!1,error:e.message}}}async set(e,t,i){try{log3.info("Setting global config",{workspacePath:e,key:t});const s=this.workspaceAdapter.getWorkspaceAppService(),r=await s.loadWorkspace(e);return await r.setConfig(t,i),await s.saveWorkspace(r),{success:!0,message:`Configuration updated: ${t}`,data:{key:t,value:i}}}catch(e){return log3.error("Failed to set global config",e),{success:!1,error:e.message}}}async list(e){try{log3.info("Listing global config",{workspacePath:e});const t=this.workspaceAdapter.getWorkspaceAppService(),i=await t.loadWorkspace(e);return{success:!0,data:{config:await i.getAllConfig(),scope:"global"}}}catch(e){return log3.error("Failed to list global config",e),{success:!1,error:e.message}}}async unset(e,t){try{log3.info("Unsetting global config",{workspacePath:e,key:t});const i=this.workspaceAdapter.getWorkspaceAppService(),s=await i.loadWorkspace(e);return await s.unsetConfig(t)?(await i.saveWorkspace(s),{success:!0,message:`Configuration deleted: ${t}`,data:{key:t}}):{success:!1,error:`Configuration key not found: ${t}`}}catch(e){return log3.error("Failed to unset global config",e),{success:!1,error:e.message}}}async getConfigPath(e){try{const t=this.workspaceAdapter.getWorkspaceAppService();return{success:!0,data:{path:(await t.loadWorkspace(e)).getConfigPath()}}}catch(e){return log3.error("Failed to get global config path",e),{success:!1,error:e.message}}}};init_server_config(),init_browser_manager();var log5=getDomainLogger("identity-app",{component:"application"}),IdentityAppService=class{constructor(e){__publicField(this,"userFactory"),__publicField(this,"currentUser",null),__publicField(this,"cachedServerConfig",null),this.userFactory=e.userFactory}async initialize(){try{this.currentUser=await this.userFactory.load(),this.currentUser?this.cachedServerConfig=this.currentUser.getServerConfig():log5.debug("No existing user session")}catch(e){log5.error("Failed to initialize identity service",e)}}async login(e,t){const i=await this.userFactory.login(e,t,this.cachedServerConfig||void 0);return this.currentUser=i,this.cachedServerConfig=i.getServerConfig(),i}async register(e,t){const i=await this.userFactory.register(e,t,this.cachedServerConfig||void 0);return this.currentUser=i,this.cachedServerConfig=i.getServerConfig(),i}async logout(){await this.userFactory.logout(),this.currentUser=null}getCurrentUser(){return this.currentUser}isAuthenticated(){return this.currentUser?.isAuthenticated()||!1}getToken(){return this.currentUser?.getToken()?.getValue()||null}getStatus(){return this.currentUser?this.currentUser.getStatus():{isAuthenticated:!1,email:"",serverUrl:this.getServerConfig().getApiUrl(),tokenExpired:!0,hasToken:!1,hasLicense:!1,license:void 0,licenseValid:!1,isTrial:!1,licensePlan:void 0,licenseExpires:void 0,licenseDaysRemaining:void 0,hasSyncConfig:!1,syncConfig:void 0}}getServerConfig(){return this.currentUser?this.currentUser.getServerConfig():this.cachedServerConfig||ServerConfig.createDefault()}async updateServerConfig(e){this.currentUser||(this.currentUser=this.userFactory.createAnonymous()),await this.userFactory.updateServerConfig(this.currentUser,e),this.cachedServerConfig=this.currentUser.getServerConfig()}async requestTrial(e){return this.userFactory.requestTrialLicense(e,this.cachedServerConfig||void 0)}async loginWithLicense(e){const t=await this.userFactory.loginWithLicense(e,this.cachedServerConfig||void 0);return this.currentUser=t,this.cachedServerConfig=t.getServerConfig(),t}async activateLicense(e,t){if(!this.currentUser)throw new Error("User must be logged in to activate license");const i=await this.userFactory.activateLicense(this.currentUser,e,t);return this.currentUser=i,i}async requestAndActivateTrial(e){const t=await this.userFactory.requestAndActivateTrial(e,this.cachedServerConfig||void 0);return this.currentUser=t,this.cachedServerConfig=t.getServerConfig(),t}getLicense(){return this.currentUser?.getLicense()||null}hasValidLicense(){return this.currentUser?.hasValidLicense()||!1}isTrialAccount(){return this.currentUser?.isTrialAccount()||!1}getLicenseDisplay(){const e=this.getLicense();return e?{key:e.getMaskedKey(),plan:e.getFormattedPlan(),expires:e.getFormattedExpiresAt(),daysRemaining:e.getDaysRemaining(),isValid:e.isValid(),isExpired:e.isExpired(),isTrial:e.isTrial(),features:e.getFeatures()}:null}async refreshTokenIfNeeded(){if(!this.currentUser)return log5.debug("No current user, cannot refresh token"),!1;const e=this.currentUser.getToken(),t=await this.userFactory.refreshTokenIfNeeded(this.currentUser),i=t.getToken(),s=e?.getValue()!==i?.getValue();return s&&(this.currentUser=t,log5.info("Token was refreshed")),s}async requestWithAutoRefresh(e){if(!this.currentUser)throw new Error("User must be logged in to make authenticated requests");const t=await this.userFactory.requestWithAutoRefresh(this.currentUser,e),i=await this.userFactory.load();return i&&(this.currentUser=i),t}async getLicenseUsage(){if(!this.currentUser)throw new Error("User must be logged in to get license usage");return this.userFactory.getLicenseUsage(this.currentUser)}async getLicenseInfo(e){if(!this.currentUser)throw new Error("User must be logged in to get license info");return this.userFactory.getLicenseInfo(this.currentUser,e)}async resetUsage(){if(!this.currentUser)throw new Error("User must be logged in to reset usage");return this.userFactory.resetUsage(this.currentUser)}async getDomains(){if(!this.currentUser)throw new Error("User must be logged in to get domains");return this.userFactory.getDomains(this.currentUser)}async checkSubdomainAvailability(e){if(!this.currentUser)throw new Error("User must be logged in to check subdomain");return this.userFactory.checkSubdomainAvailability(this.currentUser,e)}async updateSubdomain(e){if(!this.currentUser)throw new Error("User must be logged in to update subdomain");return this.userFactory.updateSubdomain(this.currentUser,e)}async checkCustomDomain(e){if(!this.currentUser)throw new Error("User must be logged in to check custom domain");return this.userFactory.checkCustomDomain(this.currentUser,e)}async addCustomDomain(e){if(!this.currentUser)throw new Error("User must be logged in to add custom domain");return this.userFactory.addCustomDomain(this.currentUser,e)}async checkCustomDomainHttpsStatus(e){if(!this.currentUser)throw new Error("User must be logged in to check HTTPS status");return this.userFactory.checkCustomDomainHttpsStatus(this.currentUser,e)}};init_browser_manager();var log6=getDomainLogger("workspace-app",{component:"application"}),WorkspaceAppService=class{constructor(e){__publicField(this,"workspaceFactory"),this.workspaceFactory=e.workspaceFactory}async loadWorkspace(e){return e?this.workspaceFactory.load(e):this.workspaceFactory.loadOrFind()}async createWorkspace(e,t){return this.workspaceFactory.create(e,t)}async saveWorkspace(e){return this.workspaceFactory.save(e)}async findWorkspaceRoot(e){return this.workspaceFactory.findWorkspaceRoot(e||process.cwd())}async createProject(e,t,i){return this.workspaceFactory.createProject(e,t,i)}async createProjectFromFolder(e,t,i,s){return this.workspaceFactory.createProjectFromFolder(e,t,i,s)}async createProjectFromFile(e,t,i,s){return this.workspaceFactory.createProjectFromFile(e,t,i,s)}async deleteProject(e,t,i){return this.workspaceFactory.deleteProject(e,t,i)}async loadWorkspaceAndProject(e,t){const i=await this.loadWorkspace(t);let s;if(e){if(s=i.findProject(e),!s){const t=i.getProjects(),r=this.workspaceFactory.fileSystemRepo;if(r){const i=r.resolvePathSync(e);for(const e of t){const t=e.getPath();if(i.startsWith(t)||t===i){s=e;break}try{const a=await r.resolvePath(i),n=await r.resolvePath(t);if(a.startsWith(n)||n===a){s=e;break}}catch(e){}}}else s=void 0;if(!s)throw new Error(`Project not found: ${e}`)}}else{const e=process.cwd(),t=i.getProjects(),r=this.workspaceFactory.fileSystemRepo;if(r)for(const i of t){const t=i.getPath();if(e.startsWith(t)){s=i;break}try{const a=await r.resolvePath(e),n=await r.resolvePath(t);if(a.startsWith(n)){s=i;break}}catch(e){}}if(s||1!==t.length||(s=t[0]),!s){if(0===t.length)throw new Error("No projects found in workspace");throw new Error(`Project not found in current directory: ${e}\nPlease specify a project name with --project <name>`)}}return log6.debug("Loaded workspace and project",{workspaceId:i.getId(),projectId:s.getId(),projectName:s.getName()}),{workspace:i,project:s}}async createSnapshot(e,t){return this.workspaceFactory.createSnapshot(e,t)}async listSnapshots(e){return this.workspaceFactory.listSnapshots(e)}async restoreSnapshot(e,t,i){return this.workspaceFactory.restoreSnapshot(e,t,i)}async deleteSnapshot(e,t){return this.workspaceFactory.deleteSnapshot(e,t)}async getSnapshot(e,t){return this.workspaceFactory.getSnapshot(e,t)}async loadProject(e){return this.workspaceFactory.loadProject(e)}async saveProject(e){return this.workspaceFactory.saveProject(e)}async findProjectRoot(e){return this.workspaceFactory.findProjectRoot(e)}async scanFolderStructure(e){return this.workspaceFactory.scanFolderStructure(e)}createIdentityStorage(e){return this.workspaceFactory.createIdentityStorage(e)}async setupProjectBaseURLStructure(e){return this.workspaceFactory.setupBaseURLStructure(e)}async cleanProjectBaseURLStructure(e){return this.workspaceFactory.cleanBaseURLStructure(e)}async ensureProjectBaseURLStructure(e){return this.workspaceFactory.ensureBaseURLStructure(e)}},WorkspaceMetadata=class e{constructor(e){__publicField(this,"version"),__publicField(this,"id"),__publicField(this,"name"),__publicField(this,"createdAt"),__publicField(this,"updatedAt"),__publicField(this,"paths"),__publicField(this,"defaults"),this.version=e.version,this.id=e.id,this.name=e.name,this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this.paths={...e.paths},this.defaults=e.defaults?{...e.defaults}:{}}static create(t){if(!t.id||!t.name)throw new Error("Workspace ID and name are required");return new e(t)}update(t){return new e({...this,...t,updatedAt:Date.now()})}toJSON(){const e={version:this.version,id:this.id,name:this.name,createdAt:this.createdAt,updatedAt:this.updatedAt,paths:{...this.paths}};return this.defaults&&Object.keys(this.defaults).length>0&&(e.defaults={...this.defaults}),e}},FolderStructure=class e{constructor(e,t,i,s){__publicField(this,"rootPath"),__publicField(this,"contentFolders"),__publicField(this,"staticFolder"),__publicField(this,"isStructured"),this.rootPath=e,this.contentFolders=t,this.staticFolder=i,this.isStructured=s}static fromScanResult(t){return new e(t.rootPath,t.contentFolders,t.staticFolder,t.isStructured)}static createEmpty(t){return new e(t,[],null,!1)}static createSingleContent(t,i,s="en"){return new e(t,[{path:i,languageCode:s,weight:0}],null,!0)}getRootPath(){return this.rootPath}getContentFolders(){return[...this.contentFolders]}getStaticFolder(){return this.staticFolder?{...this.staticFolder}:null}getIsStructured(){return this.isStructured}hasContentFolders(){return this.contentFolders.length>0}hasStaticFolder(){return null!==this.staticFolder}getContentFolderCount(){return this.contentFolders.length}getDefaultContentFolder(){return this.contentFolders.find(e=>0===e.weight)||null}getLanguageContentFolders(){return this.contentFolders.filter(e=>e.weight>0)}getContentFolderByLanguage(e){return this.contentFolders.find(t=>t.languageCode===e)||null}getSupportedLanguages(){return this.contentFolders.map(e=>e.languageCode)}isValid(){return!this.isStructured||this.contentFolders.length>0}isMultilingual(){return this.contentFolders.length>1}getSummary(){if(!this.isStructured)return`Empty structure at ${this.rootPath}`;const e=[];if(e.push(`Structured folder at ${this.rootPath}:`),e.push(` - ${this.contentFolders.length} content folder(s)`),this.isMultilingual()){const t=this.getSupportedLanguages().join(", ");e.push(` Languages: ${t}`)}return this.staticFolder&&e.push(" - static folder"),e.join("\n")}toJSON(){return{rootPath:this.rootPath,contentFolders:this.contentFolders,staticFolder:this.staticFolder,isStructured:this.isStructured}}static fromJSON(t){return e.fromScanResult(t)}};init_browser_manager();var log7=getDomainLogger("workspace",{component:"domain"}),Workspace2=class{constructor(e,t,i,s,r){if(__publicField(this,"rootPath"),__publicField(this,"metadata"),__publicField(this,"projects"),__publicField(this,"authentication"),__publicField(this,"fileSystemRepo"),this.rootPath=e,this.metadata=t,this.projects=i,this.authentication=s,this.fileSystemRepo=r,!this.fileSystemRepo)throw new Error("FileSystemRepository is required for Workspace")}getPath(){return this.rootPath}getMetadata(){return this.metadata}getId(){return this.metadata.id}getName(){return this.metadata.name}getModulesDir(){return this.fileSystemRepo.join(this.rootPath,this.metadata.paths.modules)}getProjectsDir(){return this.fileSystemRepo.join(this.rootPath,this.metadata.paths.projects)}updateMetadata(e){this.metadata=this.metadata.update(e),log7.debug("Workspace metadata updated",{workspaceId:this.getId()})}updateName(e){this.updateMetadata({name:e})}getProjects(){return Array.from(this.projects.values())}getProject(e){return this.projects.get(e)}getProjectByName(e){for(const t of this.projects.values())if(t.getName()===e)return t}findProject(e){return this.getProject(e)||this.getProjectByName(e)}hasProject(e){return this.projects.has(e)}addProject(e){if(this.projects.has(e.getId()))throw new Error(`Project ${e.getId()} already exists in workspace`);this.projects.set(e.getId(),e),log7.info(`Project added to workspace: ${e.getName()} (${e.getId()})`)}removeProject(e){const t=this.projects.get(e);return t?(this.projects.delete(e),log7.info(`Project removed from workspace: ${t.getName()} (${e})`),t):null}getProjectCount(){return this.projects.size}getProjectRegistry(){const e=[];for(const t of this.projects.values()){const i=t.getMetadata(),s=t.getPath(),r=this.fileSystemRepo.relative(this.getProjectsDir(),s);e.push({id:i.id,name:i.name,path:r,absolutePath:s,createdAt:i.createdAt,updatedAt:i.updatedAt,status:"active"})}return{version:"1.0",projects:e}}getAuthentication(){return this.authentication}hasAuthentication(){return this.authentication.hasAuth()}getConfigPath(){return this.fileSystemRepo.join(this.rootPath,".mdfriday","config.json")}async getConfig(e){const t=this.getConfigPath();try{const i=await this.fileSystemRepo.readFile(t,"utf-8"),s=JSON.parse(i);return this.getNestedValue(s,e)}catch(e){if(e.message?.includes("Cannot access path"))return;throw e}}async getAllConfig(){const e=this.getConfigPath();try{const t=await this.fileSystemRepo.readFile(e,"utf-8");return JSON.parse(t)}catch(e){if(e.message?.includes("Cannot access path"))return{};throw e}}async setConfig(e,t){const i=this.getConfigPath(),s=this.fileSystemRepo.dirname(i);await this.fileSystemRepo.createDirectory(s,!0);let r={};try{const e=await this.fileSystemRepo.readFile(i,"utf-8");r=JSON.parse(e)}catch(e){if(!e.message?.includes("Cannot access path"))throw e}this.setNestedValue(r,e,t),await this.fileSystemRepo.writeFile(i,JSON.stringify(r,null,2),"utf-8"),log7.debug(`Workspace config updated: ${e}`,{workspaceId:this.getId()})}async unsetConfig(e){const t=this.getConfigPath();try{const i=await this.fileSystemRepo.readFile(t,"utf-8"),s=JSON.parse(i),r=this.deleteNestedValue(s,e);return r&&(await this.fileSystemRepo.writeFile(t,JSON.stringify(s,null,2),"utf-8"),log7.debug(`Workspace config deleted: ${e}`,{workspaceId:this.getId()})),r}catch(e){if(e.message?.includes("Cannot access path"))return!1;throw e}}getNestedValue(e,t){const i=t.split(".");let s=e;for(const e of i){if(null==s||"object"!=typeof s)return;s=s[e]}return s}setNestedValue(e,t,i){const s=t.split(".");let r=e;for(let e=0;e<s.length-1;e++){const t=s[e];t in r&&"object"==typeof r[t]||(r[t]={}),r=r[t]}r[s[s.length-1]]=i}deleteNestedValue(e,t){const i=t.split(".");let s=e;for(let e=0;e<i.length-1;e++){const t=i[e];if(!(t in s)||"object"!=typeof s[t])return!1;s=s[t]}const r=i[i.length-1];return r in s&&(delete s[r],!0)}getInfo(){return{id:this.metadata.id,name:this.metadata.name,path:this.rootPath,createdAt:new Date(this.metadata.createdAt),updatedAt:new Date(this.metadata.updatedAt),modulesDir:this.metadata.paths.modules,projectsDir:this.metadata.paths.projects,projectCount:this.projects.size,hasAuth:this.authentication.hasAuth()}}};init_browser_manager();var log8=getDomainLogger("project",{component:"domain"}),Project3=class{constructor(e,t,i){if(__publicField(this,"metadata"),__publicField(this,"projectPath"),__publicField(this,"config",null),__publicField(this,"fileSystemRepo"),this.projectPath=e,this.metadata=t,this.fileSystemRepo=i,!this.fileSystemRepo)throw new Error("FileSystemRepository is required for Project")}getPath(){return this.projectPath}getMetadata(){return this.metadata}getId(){return this.metadata.id}getName(){return this.metadata.name}getWorkspaceId(){return this.metadata.workspaceId}getBuildHistory(){return this.metadata.buildHistory||[]}addBuildHistory(e){const t=[e,...this.metadata.buildHistory||[]],i=t.length>50?t.slice(0,50):t;this.metadata=this.metadata.update({buildHistory:i}),log8.debug(`Added build history entry for project: ${this.metadata.name}`)}getLastBuildTime(){const e=this.getBuildHistory();return e.length>0?e[0].timestamp:void 0}updateName(e){this.metadata=this.metadata.update({name:e})}async loadConfig(){if(this.config)return this.config;try{const e=this.fileSystemRepo.join(this.projectPath,"config.json"),t=await this.fileSystemRepo.readFile(e,"utf-8");return this.config=JSON.parse(t),this.config}catch(e){return log8.warn(`Failed to load config for project ${this.metadata.name}, using defaults`),this.config={contentDir:"content",publishDir:"public",defaultContentLanguage:"zh"},this.config}}getConfig(){return this.config}async getContentDirs(){const e=await this.loadConfig(),t=[],i=e.contentDir||"content";if(t.push(this.fileSystemRepo.join(this.projectPath,i)),e.languages)for(const[s,r]of Object.entries(e.languages))r.contentDir&&r.contentDir!==i&&t.push(this.fileSystemRepo.join(this.projectPath,r.contentDir));return[...new Set(t)]}async getPublishDir(){const e=(await this.loadConfig()).publishDir||"public";return this.fileSystemRepo.join(this.projectPath,e)}getStaticDir(){return this.fileSystemRepo.join(this.projectPath,"static")}async getDefaultLanguage(){return(await this.loadConfig()).defaultContentLanguage||"zh"}async getLanguages(){const e=await this.loadConfig();return e.languages?Object.keys(e.languages):[await this.getDefaultLanguage()]}getConfigPath(){return this.fileSystemRepo.join(this.projectPath,"config.json")}getConfigValue(e){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");return this.getNestedValue(this.config,e)}setConfigValue(e,t){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");this.setNestedValue(this.config,e,t),log8.debug(`Project config updated: ${e}`,{projectName:this.metadata.name})}setConfig(e){if(null===this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");this.config=e,log8.debug("Project config replaced entirely",{projectName:this.metadata.name})}unsetConfigValue(e){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");const t=this.deleteNestedValue(this.config,e);return t&&log8.debug(`Project config deleted: ${e}`,{projectName:this.metadata.name}),t}async saveConfig(){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");const e=this.getConfigPath();await this.fileSystemRepo.writeFile(e,JSON.stringify(this.config,null,2),"utf-8"),log8.debug(`Project config saved: ${e}`,{projectName:this.metadata.name})}getNestedValue(e,t){const i=t.split(".");let s=e;for(const e of i){if(null==s||"object"!=typeof s)return;s=s[e]}return s}setNestedValue(e,t,i){const s=t.split(".");let r=e;for(let e=0;e<s.length-1;e++){const t=s[e];t in r&&"object"==typeof r[t]&&!Array.isArray(r[t])||(r[t]={}),r=r[t]}r[s[s.length-1]]=i}deleteNestedValue(e,t){const i=t.split(".");let s=e;for(let e=0;e<i.length-1;e++){const t=i[e];if(!(t in s)||"object"!=typeof s[t])return!1;s=s[t]}const r=i[i.length-1];return r in s&&(delete s[r],!0)}getInfo(){const e=this.getLastBuildTime(),t={id:this.metadata.id,name:this.metadata.name,path:this.projectPath,createdAt:new Date(this.metadata.createdAt),updatedAt:new Date(this.metadata.updatedAt),buildCount:this.getBuildHistory().length};return e&&(t.lastBuild=new Date(e)),t}getSnapshotsDir(){return this.fileSystemRepo.join(this.projectPath,".mdfriday","snapshots")}hasSourceLinks(){return this.metadata.contentLinks.length>0||null!==this.metadata.staticLink}getContentLinks(){return[...this.metadata.contentLinks]}getStaticLink(){return this.metadata.staticLink?{...this.metadata.staticLink}:null}getFileLink(){return this.metadata.fileLink?{...this.metadata.fileLink}:null}setContentLinks(e){this.metadata=this.metadata.update({contentLinks:e}),log8.debug(`Updated content links for project: ${this.metadata.name}`,{count:e.length})}setStaticLink(e){this.metadata=this.metadata.update({staticLink:e}),log8.debug(`Updated static link for project: ${this.metadata.name}`,{hasLink:null!==e})}addContentLink(e,t,i){const s=[...this.getContentLinks(),{sourcePath:e,languageCode:t,weight:i}];this.setContentLinks(s)}getDefaultContentSource(){const e=this.metadata.contentLinks.find(e=>0===e.weight);return e?e.sourcePath:null}getAllContentSources(){return this.metadata.contentLinks.map(e=>e.sourcePath)}getContentSourceByLanguage(e){const t=this.metadata.contentLinks.find(t=>t.languageCode===e);return t?t.sourcePath:null}getSupportedLanguagesFromLinks(){return this.metadata.contentLinks.map(e=>e.languageCode)}isLinkedProject(){return this.hasSourceLinks()}getLinkDirs(){const e=[],t=this.getFileLink();t&&e.push(t.sourcePath);const i=this.getContentLinks();for(const t of i)e.includes(t.sourcePath)||e.push(t.sourcePath);return e}async getBaseURL(){return(await this.loadConfig()).baseURL||"/"}async setBaseURL(e){const t=await this.loadConfig();t.baseURL=e;const i=this.fileSystemRepo.join(this.projectPath,"config.json");await this.fileSystemRepo.writeFile(i,JSON.stringify(t,null,2),"utf-8"),this.config=t}parseBaseURLPath(e){let t=e.trim();if(t.startsWith("/")&&(t=t.slice(1)),t.endsWith("/")&&(t=t.slice(0,-1)),""===t)return{isRoot:!0,pathParts:[],parentParts:[],finalDirName:"",relativeToPublic:"."};const i=t.split("/").filter(e=>""!==e);if(0===i.length)return{isRoot:!0,pathParts:[],parentParts:[],finalDirName:"",relativeToPublic:"."};const s=i.length,r=1===s?".":"../".repeat(s-1).slice(0,-1);return{isRoot:!1,pathParts:i,parentParts:i.slice(0,-1),finalDirName:i[i.length-1],relativeToPublic:r}}getBaseURLStructure(){return this.metadata.baseURLStructure||null}updateBaseURLStructure(e){this.metadata=this.metadata.update({baseURLStructure:e})}};init_browser_manager(),getDomainLogger("workspace-auth",{component:"domain"});var Authentication2=class{constructor(e,t=!1){__publicField(this,"workspacePath"),__publicField(this,"hasAuthFile",!1),this.workspacePath=e,this.hasAuthFile=t}getWorkspacePath(){return this.workspacePath}hasAuth(){return this.hasAuthFile}markAuthExists(){this.hasAuthFile=!0}markAuthDeleted(){this.hasAuthFile=!1}getAuthFilePath(){return".mdfriday/auth-user.json"}getServerConfigPath(){return".mdfriday/server-config.json"}};init_project_metadata(),init_browser_manager();var log10=getDomainLogger("workspace-factory",{component:"domain"});function generateProjectId(e){return`${e.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"")}-${Date.now().toString(36)}`}var WorkspaceFactory2=class{constructor(e){if(__publicField(this,"workspaceRepo"),__publicField(this,"projectRepo"),__publicField(this,"snapshotRepo"),__publicField(this,"fileSystemRepo"),this.workspaceRepo=e.workspaceRepo,this.projectRepo=e.projectRepo,this.snapshotRepo=e.snapshotRepo,this.fileSystemRepo=e.fileSystemRepo,!this.fileSystemRepo)throw new Error("FileSystemRepository is required")}async load(e){const t=this.fileSystemRepo.resolvePathSync(e);log10.info("Loading workspace",{path:t});const i=await this.workspaceRepo.loadWorkspaceMetadata(t),s=WorkspaceMetadata.create(i),r=await this.workspaceRepo.loadProjectRegistry(t),a=new Map;for(const e of r.projects)try{const t=await this.projectRepo.loadProjectMetadata(e.absolutePath),i=ProjectMetadata.create(t),s=new Project3(e.absolutePath,i,this.fileSystemRepo);a.set(e.id,s),log10.debug("Project loaded",{projectId:e.id,name:e.name})}catch(t){log10.warn("Failed to load project, skipping",{projectId:e.id,path:e.absolutePath,error:t.message})}const n=await this.checkAuthFile(t),o=new Authentication2(t,n),c=new Workspace2(t,s,a,o,this.fileSystemRepo);return log10.info("Workspace loaded",{workspaceId:c.getId(),name:c.getName(),projectCount:c.getProjectCount()}),c}async checkAuthFile(e){const t=this.fileSystemRepo.join(e,".mdfriday","auth-token.json");try{return await this.fileSystemRepo.access(t),!0}catch{return!1}}async create(e,t={}){const i=this.fileSystemRepo.resolvePathSync(e);if(log10.info("Creating workspace",{path:i}),await this.workspaceRepo.isWorkspace(i))throw new Error(`Workspace already exists at ${i}`);const s=t.modulesDir||"modules",r=t.projectsDir||"projects";await this.workspaceRepo.initWorkspaceStructure(i,s,r);const a=Date.now(),n=WorkspaceMetadata.create({version:"1.0",id:`workspace-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,name:t.name||this.fileSystemRepo.basename(i),createdAt:a,updatedAt:a,paths:{modules:s,projects:r},defaults:{modulesDir:s,language:"en"}});await this.workspaceRepo.saveWorkspaceMetadata(i,n.toJSON()),await this.workspaceRepo.saveProjectRegistry(i,{version:"1.0",projects:[]});const o=this.fileSystemRepo.join(i,".mdfriday"),c=this.fileSystemRepo.join(o,"config.json");await this.fileSystemRepo.writeFile(c,"{}","utf-8");const l=this.fileSystemRepo.join(o,"user-data.json");await this.fileSystemRepo.writeFile(l,"{}","utf-8"),log10.debug("Initialized configuration files",{configPath:c,userDataPath:l});const u=new Authentication2(i,!1),d=new Workspace2(i,n,new Map,u,this.fileSystemRepo);return log10.info("Workspace created",{workspaceId:d.getId(),name:d.getName()}),d}async save(e){const t=e.getPath();log10.info("Saving workspace",{workspaceId:e.getId(),path:t}),await this.workspaceRepo.saveWorkspaceMetadata(t,e.getMetadata().toJSON());const i=e.getProjectRegistry();await this.workspaceRepo.saveProjectRegistry(t,i);for(const t of e.getProjects())await this.projectRepo.saveProjectMetadata(t.getPath(),t.getMetadata().toJSON());log10.info("Workspace saved",{workspaceId:e.getId(),projectCount:e.getProjectCount()})}async findWorkspaceRoot(e){let t=this.fileSystemRepo.resolvePathSync(e);const i=this.fileSystemRepo.parsePath(t).root;for(;t!==i;){if(await this.workspaceRepo.isWorkspace(t))return t;t=this.fileSystemRepo.dirname(t)}return null}async isWorkspace(e){const t=this.fileSystemRepo.resolvePathSync(e);return this.workspaceRepo.isWorkspace(t)}async loadOrFind(e){const t=e||process.cwd(),i=await this.findWorkspaceRoot(t);if(!i)throw new Error('No workspace found. Run "mdf workspace init" to create one.');return this.load(i)}async createProject(e,t,i={}){const s=generateProjectId(t),r=this.fileSystemRepo.join(e.getProjectsDir(),t);if(log10.info("Creating project",{projectId:s,name:t,path:r}),e.findProject(t))throw new Error(`Project ${t} already exists`);const a=i.contentDir||"content",n=i.staticDir||"static",o=i.publishDir||"public";await this.projectRepo.initProjectStructure(r,a,n,o);const c=Date.now(),l=ProjectMetadata.create({id:s,name:t,workspaceId:e.getId(),createdAt:c,updatedAt:c}),u=i.theme||"https://gohugo.net/quartz-theme.zip?version=1.2",d={baseURL:i.baseURL||"/",title:t,contentDir:a,publishDir:o,defaultContentLanguage:i.language||"en",module:{imports:[{path:u}]}};await this.projectRepo.saveProjectMetadata(r,l.toJSON()),await this.projectRepo.saveProjectConfig(r,d);const h=this.fileSystemRepo.join(r,a,"index.md");await this.projectRepo.createSampleContent(h,this.createSampleContent());const g=new Project3(r,l,this.fileSystemRepo);return e.addProject(g),await this.save(e),log10.info("Project created",{projectId:s,name:t}),g}async deleteProject(e,t,i={}){const s=e.findProject(t);if(!s)throw new Error(`Project not found: ${t}`);log10.info("Deleting project",{projectId:s.getId(),name:s.getName(),deleteFiles:i.deleteFiles}),e.removeProject(s.getId()),await this.save(e),i.deleteFiles&&(await this.projectRepo.deleteProjectFiles(s.getPath()),log10.info("Project files deleted",{projectId:s.getId()})),log10.info("Project deleted",{projectId:s.getId(),name:s.getName()})}async createProjectFromFolder(e,t,i,s={}){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to create project from folder");const r=generateProjectId(t),a=this.fileSystemRepo.join(e.getProjectsDir(),t);if(log10.info("Creating project from folder",{projectId:r,name:t,sourcePath:i,targetPath:a}),e.findProject(t))throw new Error(`Project ${t} already exists`);const n=await this.fileSystemRepo.scanFolderStructure(i),o=FolderStructure.fromScanResult(n);let c;log10.debug("Scanned folder structure",{isStructured:o.getIsStructured(),contentFolders:o.getContentFolderCount(),hasStatic:o.hasStaticFolder()}),o.getIsStructured()&&0!==o.getContentFolderCount()?c=o:(log10.info("No standard structure found, treating source folder as content directory"),c=FolderStructure.createSingleContent(i,i,s.language||"en")),await this.projectRepo.initProjectStructure(a,"content","static","public");const l=[],u=[];for(const e of c.getContentFolders()){const t=0===e.weight?this.fileSystemRepo.join(a,"content"):this.fileSystemRepo.join(a,`content.${e.languageCode}`);l.push({source:e.path,target:t}),u.push({sourcePath:e.path,languageCode:e.languageCode,weight:e.weight})}let d=null;if(c.hasStaticFolder()){const e=c.getStaticFolder();l.push({source:e.path,target:this.fileSystemRepo.join(a,"static")}),d={sourcePath:e.path}}const h=(await this.fileSystemRepo.createSymlinks(l)).filter(e=>!e.success);if(h.length>0)throw log10.error("Some symlinks failed to create",{failed:h}),new Error(`Failed to create symlinks: ${h.map(e=>e.error).join(", ")}`);const g=Date.now(),p=ProjectMetadata.create({id:r,name:t,workspaceId:e.getId(),createdAt:g,updatedAt:g,contentLinks:u,staticLink:d}),f=s.theme||"https://gohugo.net/quartz-theme.zip?version=1.2",m={baseURL:"/",title:t,contentDir:"content",publishDir:"public",defaultContentLanguage:c.getDefaultContentFolder()?.languageCode||s.language||"en",module:{imports:[{path:f}]}};if(c.hasContentFolders()){const e={};for(const t of c.getContentFolders()){const i=0===t.weight?"content":`content.${t.languageCode}`;e[t.languageCode]={contentDir:i,weight:t.weight+1}}m.languages=e}await this.projectRepo.saveProjectMetadata(a,p.toJSON()),await this.projectRepo.saveProjectConfig(a,m);const y=new Project3(a,p,this.fileSystemRepo);return e.addProject(y),await this.save(e),log10.info("Project created from folder",{projectId:r,name:t,linkedContentFolders:u.length,hasStaticLink:null!==d}),y}async createProjectFromFile(e,t,i,s={}){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to create project from file");const r=generateProjectId(t),a=this.fileSystemRepo.join(e.getProjectsDir(),t);if(log10.info("Creating project from file",{projectId:r,name:t,sourceFile:i,targetPath:a}),e.findProject(t))throw new Error(`Project ${t} already exists`);if(!await this.fileSystemRepo.exists(i))throw new Error(`Source file not found: ${i}`);if(!(await this.fileSystemRepo.stat(i)).isFile())throw new Error(`Source path is not a file: ${i}`);await this.projectRepo.initProjectStructure(a,"content","static","public");const n=this.fileSystemRepo.join(a,"content"),o=this.fileSystemRepo.join(n,"index.md");let c=!1,l=null;try{await this.fileSystemRepo.exists(n)&&await this.fileSystemRepo.remove(n,!0),await this.fileSystemRepo.createDirectory(n,!0);const e=await this.fileSystemRepo.createSymlink(i,o);if(!e.success)throw new Error(e.error||"Failed to create symlink");c=!0,l={source:i,target:o},log10.info("Created symlink for file",{source:i,target:o})}catch(e){log10.warn("Symlink creation failed, falling back to file copy",{error:e});try{await this.fileSystemRepo.copyFile(i,o),log10.info("Copied file as fallback",{source:i,target:o})}catch(e){throw log10.error("Failed to copy file",e),new Error(`Failed to create file link or copy: ${e.message}`)}}const u=Date.now(),d=ProjectMetadata.create({id:r,name:t,workspaceId:e.getId(),createdAt:u,updatedAt:u,fileLink:l?{sourcePath:l.source,targetPath:l.target,isSymlink:c}:null}),h=s.theme||"https://gohugo.net/note.zip?version=1.2",g={baseURL:"/",title:t,contentDir:"content",publishDir:"public",defaultContentLanguage:s.language||"en",module:{imports:[{path:h}]}};await this.projectRepo.saveProjectMetadata(a,d.toJSON()),await this.projectRepo.saveProjectConfig(a,g);const p=new Project3(a,d,this.fileSystemRepo);return e.addProject(p),await this.save(e),log10.info("Project created from file",{projectId:r,name:t,sourceFile:i,useSymlink:c}),p}async loadProject(e){const t=this.fileSystemRepo.resolvePathSync(e);if(!await this.projectRepo.isProject(t))throw new Error(`No project found at ${t}`);const i=await this.projectRepo.loadProjectMetadata(t),{ProjectMetadata:s}=await Promise.resolve().then(()=>(init_project_metadata(),project_metadata_exports)),r=s.create(i);return new Project3(t,r,this.fileSystemRepo)}async saveProject(e){const t=e.getPath();await this.projectRepo.saveProjectMetadata(t,e.getMetadata().toJSON()),e.getConfig()&&await e.saveConfig(),log10.debug(`Saved project: ${e.getName()}`)}async findProjectRoot(e){let t=this.fileSystemRepo.resolvePathSync(e);const i=this.fileSystemRepo.parsePath(t).root;for(;t!==i;){if(await this.projectRepo.isProject(t))return t;t=this.fileSystemRepo.dirname(t)}return null}async createSnapshot(e,t){const i=e.getPath(),s=await e.getPublishDir(),r=`${(new Date).toISOString().replace(/[:.]/g,"-").split(".")[0]}Z`;log10.info("Creating snapshot",{projectId:e.getId(),snapshotId:r});const a=await this.snapshotRepo.createSnapshot(i,r,s);if(t&&t!==a.id){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to update snapshot metadata");a.name=t;const i=this.fileSystemRepo.join(e.getPath(),".mdfriday","snapshots",`${a.id}.json`);await this.fileSystemRepo.writeFile(i,JSON.stringify(a,null,2))}return log10.info("Snapshot created",{snapshotId:r,size:a.size,fileCount:a.fileCount}),a}async listSnapshots(e){return(await this.snapshotRepo.listSnapshots(e.getPath())).sort((e,t)=>t.timestamp-e.timestamp)}async restoreSnapshot(e,t,i){const s=i||await e.getPublishDir();await this.snapshotRepo.restoreSnapshot(e.getPath(),t,s)}async deleteSnapshot(e,t){await this.snapshotRepo.deleteSnapshot(e.getPath(),t)}async getSnapshot(e,t){return await this.snapshotRepo.getSnapshot(e.getPath(),t)}createIdentityStorage(e){const t=e.getPath(),i=e.getAuthentication(),s=this.fileSystemRepo;if(!s)throw new Error("FileSystemRepository is required for identity storage");return{async saveUserData(e){const r=s.join(t,".mdfriday","user-data.json");await s.createDirectory(s.dirname(r),!0);const a={};e.serverConfig&&(a.serverConfig=e.serverConfig.toJSON()),e.token&&(a.token=e.token.toJSON(),i.markAuthExists()),e.license&&(a.license=e.license.toJSON()),e.syncConfig&&(a.syncConfig=e.syncConfig.toJSON()),e.email&&(a.email=e.email),await s.writeFile(r,JSON.stringify(a,null,2))},async loadUserData(){const e=s.join(t,".mdfriday","user-data.json");try{const t=await s.readFile(e,"utf-8"),i=JSON.parse(t),{Token:r,ServerConfig:a,License:n,SyncConfig:o}=await Promise.resolve().then(()=>(init_identity(),identity_exports)),c={};return i.serverConfig&&(c.serverConfig=a.create(i.serverConfig.apiUrl,i.serverConfig.websiteUrl)),i.token&&(c.token=r.create(i.token.token||i.token.value,i.token.expiresAt)),i.license&&(c.license=n.create(i.license.key,i.license.plan,i.license.expiresAt,i.license.features,i.license.activatedAt,i.license.activated,i.license.firstTime)),i.syncConfig&&(c.syncConfig=o.fromJSON(i.syncConfig)),i.email&&(c.email=i.email),c}catch{return null}},async clearUserData(){const e=s.join(t,".mdfriday","user-data.json");try{await s.unlink(e)}catch{}i.markAuthDeleted()}}}async setupBaseURLStructure(e){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required for baseURL structure");const t=await e.getBaseURL(),i=e.parseBaseURLPath(t),s=e.getPath(),r=this.fileSystemRepo.join(s,"public");if(i.isRoot)return log10.debug("baseURL is root, no structure needed"),{serverRoot:r,baseURL:"/",symlinkCreated:!1};log10.info("Creating baseURL structure in public/",{baseURL:t,pathParts:i.pathParts});let a=r;for(const e of i.parentParts)a=this.fileSystemRepo.join(a,e),await this.fileSystemRepo.exists(a)||(await this.fileSystemRepo.createDirectory(a,!1),log10.debug(`Created parent directory: ${e}`));const n=this.fileSystemRepo.join(a,i.finalDirName);await this.fileSystemRepo.exists(n)&&(await this.fileSystemRepo.remove(n,!0),log10.debug(`Removed existing symlink: ${n}`));const o=await this.fileSystemRepo.createSymlink(i.relativeToPublic,n);if(!o.success)throw log10.error("Failed to create baseURL symlink",{target:i.relativeToPublic,link:n,error:o.error}),new Error(`Failed to create baseURL structure: ${o.error}`);return log10.info("baseURL structure created successfully",{symlinkPath:i.pathParts.join("/"),target:i.relativeToPublic}),e.updateBaseURLStructure({baseURL:t,createdAt:Date.now(),pathParts:i.pathParts}),await this.projectRepo.saveProjectMetadata(e.getPath(),e.getMetadata().toJSON()),{serverRoot:r,baseURL:t,symlinkCreated:!0}}async cleanBaseURLStructure(e){if(!this.fileSystemRepo)return;const t=e.getBaseURLStructure();if(!t||0===t.pathParts.length)return;const i=e.getPath(),s=this.fileSystemRepo.join(i,"public");log10.info("Cleaning baseURL structure in public/",{pathParts:t.pathParts});for(let e=t.pathParts.length;e>0;e--){const i=this.fileSystemRepo.join(s,...t.pathParts.slice(0,e));if(await this.fileSystemRepo.exists(i)&&(await this.fileSystemRepo.remove(i,!0),log10.debug(`Removed: ${t.pathParts.slice(0,e).join("/")}`)),e>1){const i=this.fileSystemRepo.join(s,...t.pathParts.slice(0,e-1));if(await this.fileSystemRepo.exists(i)&&(await this.fileSystemRepo.readDirectory(i)).length>0)break}}e.updateBaseURLStructure(null),await this.projectRepo.saveProjectMetadata(e.getPath(),e.getMetadata().toJSON()),log10.info("baseURL structure cleaned")}async ensureBaseURLStructure(e){const t=await e.getBaseURL(),i=e.getBaseURLStructure();return i&&i.baseURL===t?{serverRoot:this.fileSystemRepo.join(e.getPath(),"public"),baseURL:t,recreated:!1}:(i&&(log10.info("baseURL changed, recreating structure",{old:i.baseURL,new:t}),await this.cleanBaseURLStructure(e)),{...await this.setupBaseURLStructure(e),recreated:!0})}async scanFolderStructure(e){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to scan folder structure");log10.info("Scanning folder structure",{path:e});const t=await this.fileSystemRepo.scanFolderStructure(e),i=FolderStructure.fromScanResult(t);return log10.debug("Folder structure scanned",{isStructured:i.getIsStructured(),contentFolders:i.getContentFolderCount(),hasStatic:i.hasStaticFolder(),languages:i.getSupportedLanguages()}),i}createSampleContent(){return`---\ntitle: Welcome to MDFriday\ndate: ${(new Date).toISOString()}\n---\n\n# Welcome to MDFriday\n\nThis is a sample page. Edit this file to get started!\n\n## Features\n\n- **Markdown Support**: Write content in Markdown\n- **Themes**: Beautiful themes out of the box\n- **Fast**: Static site generation for speed\n- **Flexible**: Customize everything\n\n## Getting Started\n\n1. Edit files in the \`content/\` directory\n2. Run \`mdf serve\` to preview\n3. Run \`mdf build\` to generate your site\n`}};function createObsidianWorkspaceAppService(e){if(!e)throw new Error("[Foundry Mobile] Configuration is required for Mobile environment. Please provide ObsidianMobileEnvironmentConfig with workspace and fileSystem repositories. See: docs/obsidian-mobile-implementation.md");const t=new WorkspaceFactory2({workspaceRepo:e.persistence.workspace,projectRepo:e.persistence.workspace,snapshotRepo:e.persistence.workspace,fileSystemRepo:e.persistence.fileSystem});return new WorkspaceAppService({workspaceFactory:t})}async function createObsidianIdentityService(e,t,i){if(!i)throw new Error("[Foundry Mobile] Configuration is required for Mobile environment. Please provide ObsidianMobileEnvironmentConfig. See: docs/obsidian-mobile-implementation.md");const s=createObsidianWorkspaceAppService(i),r=i?i.identityHttpClient:t,a=await s.loadWorkspace(e),n=s.createIdentityStorage(a),o=new UserFactory({httpClient:r,storageProvider:n}),c=new IdentityAppService({userFactory:o});return await c.initialize(),c}init_project_metadata(),init_identity();var MobileIdentityAdapter=class{constructor(e){this.config=e}async getIdentityService(e,t){return await createObsidianIdentityService(e,t,this.config)}},MobileWorkspaceAdapter=class{constructor(e){this.config=e,__publicField(this,"workspaceAppService")}getWorkspaceAppService(){return this.workspaceAppService||(this.workspaceAppService=createObsidianWorkspaceAppService(this.config)),this.workspaceAppService}getWorkspaceFactory(){return this.getWorkspaceAppService().workspaceFactory}getFileSystemRepository(){return this.config.persistence.fileSystem}};function createObsidianWorkspaceService(e){const t=new MobileWorkspaceAdapter(e);return new ObsidianWorkspaceService(t)}function createObsidianAuthService(e,t){const i=new MobileIdentityAdapter(t);return new ObsidianAuthService(e,i)}function createObsidianLicenseService(e,t){const i=new MobileIdentityAdapter(t);return new ObsidianLicenseService(e,i)}function createObsidianGlobalConfigService(e){const t=new MobileWorkspaceAdapter(e);return new ObsidianGlobalConfigService(t)}
2
+ var BrowserLogger,__defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropNames=Object.getOwnPropertyNames,__hasOwnProp=Object.prototype.hasOwnProperty,__esm=(e,t)=>function(){return e&&(t=(0,e[__getOwnPropNames(e)[0]])(e=0)),t},__export=(e,t)=>{for(var i in t)__defProp(e,i,{get:t[i],enumerable:!0})},__publicField=(e,t,i)=>(((e,t,i)=>{t in e?__defProp(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i})(e,"symbol"!=typeof t?t+"":t,i),i),init_types=__esm({"pkg/log/types.ts"(){}});function NewBrowser(e="info"){return new BrowserLogger({level:e})}function NewBrowserWithConfig(e){return new BrowserLogger(e)}var globalBrowserLoggerManager,init_browser=__esm({"pkg/log/browser.ts"(){init_types(),BrowserLogger=class e{constructor(e){__publicField(this,"config"),__publicField(this,"fields"),this.config={enableCaller:!1,jsonFormat:!1,...e},this.fields={}}shouldLog(e){const t=["debug","info","warn","error","fatal"],i=t.indexOf(this.config.level);return t.indexOf(e)>=i}getCaller(){if(this.config.enableCaller)try{const e=(new Error).stack;if(!e)return;const t=e.split("\n")[4];if(!t)return;const i=t.match(/at .* \((.+):(\d+):(\d+)\)/);if(i){const[,e,t]=i;return`${e.split("/").pop()}:${t}`}const s=t.match(/at (.+):(\d+):(\d+)/);if(s){const[,e,t]=s;return`${e.split("/").pop()}:${t}`}return}catch{return}}formatMessage(e,t){if(0===t.length)return e;let i=e,s=0;for(i=i.replace(/%[sdj]/g,e=>{if(s>=t.length)return e;const i=t[s++];switch(e){case"%s":return String(i);case"%d":return Number(i).toString();case"%j":try{return JSON.stringify(i)}catch{return"[Circular]"}default:return e}});s<t.length;)i+=" "+String(t[s++]);return i}writeLog(e,t){if(!this.shouldLog(e))return;const i={level:e,timestamp:(new Date).toISOString(),message:t,...this.fields},s=this.getCaller();if(s&&(i.caller=s),this.config.jsonFormat){const t=JSON.stringify(i);this.consoleOutput(e,t)}else{const t=this.formatPlainText(i);this.consoleOutput(e,t)}}consoleOutput(e,t){switch(e){case"debug":break;case"info":console.log(t);break;case"warn":console.warn(t);break;case"error":console.error(t);break;case"fatal":console.error("[FATAL]",t)}}formatPlainText(e){const t=[e.timestamp,e.level.toUpperCase()];e.caller&&t.push(`[${e.caller}]`),t.push(e.message);const i=Object.keys(e).filter(e=>!["level","timestamp","message","caller"].includes(e)).map(t=>`${t}=${JSON.stringify(e[t])}`).join(" ");return i&&t.push(i),t.join(" ")}debug(e,...t){this.writeLog("debug",this.formatMessage(e,t))}info(e,...t){this.writeLog("info",this.formatMessage(e,t))}warn(e,...t){this.writeLog("warn",this.formatMessage(e,t))}error(e,...t){this.writeLog("error",this.formatMessage(e,t))}fatal(e,...t){this.writeLog("fatal",this.formatMessage(e,t))}debugf(e,...t){this.writeLog("debug",this.formatMessage(e,t))}infof(e,...t){this.writeLog("info",this.formatMessage(e,t))}warnf(e,...t){this.writeLog("warn",this.formatMessage(e,t))}errorf(e,...t){this.writeLog("error",this.formatMessage(e,t))}fatalf(e,...t){this.writeLog("fatal",this.formatMessage(e,t))}with(t){const i=new e(this.config);return i.fields={...this.fields,...t},i}}}});function getDomainLogger(e,t){return globalBrowserLoggerManager.getDomainLogger(e,t)}var Email,Token,ServerConfig,License,SyncConfig,Device,User,log4,UserFactory,init_browser_manager=__esm({"pkg/log/browser-manager.ts"(){init_browser(),init_types(),globalBrowserLoggerManager=new class{constructor(){__publicField(this,"globalLogger"),__publicField(this,"domainLoggers"),this.globalLogger=NewBrowser("info"),this.domainLoggers=new Map}setGlobalLogLevel(e){this.globalLogger=NewBrowser(e),this.domainLoggers.clear()}setGlobalCallerEnabled(e){this.globalLogger=NewBrowserWithConfig({level:"info",enableCaller:e}),this.domainLoggers.clear()}setGlobalJsonFormat(e){this.globalLogger=NewBrowserWithConfig({level:"info",jsonFormat:e}),this.domainLoggers.clear()}getDomainLogger(e,t){const i=`${e}:${JSON.stringify(t||{})}`;if(!this.domainLoggers.has(i)){let e=this.globalLogger;t&&(e=e.with(t)),this.domainLoggers.set(i,e)}return this.domainLoggers.get(i)}getComponentLogger(e,t){return this.getDomainLogger(e,{component:e,...t})}}}}),init_email=__esm({"internal/domain/identity/value-object/email.ts"(){Email=class e{constructor(e){__publicField(this,"value"),this.value=e}static create(t){if(!e.isValid(t))throw new Error(`Invalid email address: ${t}`);return new e(t)}static isValid(e){return!(!e||"string"!=typeof e)&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}getValue(){return this.value}getDomain(){return this.value.split("@")[1]}getLocalPart(){return this.value.split("@")[0]}equals(e){return this.value.toLowerCase()===e.value.toLowerCase()}toString(){return this.value}toJSON(){return this.value}}}}),init_token=__esm({"internal/domain/identity/value-object/token.ts"(){Token=class e{constructor(e,t){__publicField(this,"value"),__publicField(this,"expiresAt"),this.value=e,this.expiresAt=t}static create(t,i){if(!t||"string"!=typeof t||0===t.trim().length)throw new Error("Token value cannot be empty");return new e(t,i)}static fromJSON(t){return e.create(t.token,t.expiresAt)}getValue(){return this.value}getExpiresAt(){return this.expiresAt}isExpired(){return!!this.expiresAt&&Date.now()>this.expiresAt}isValid(){return!this.isExpired()}getRemainingTime(){if(!this.expiresAt)return null;const e=this.expiresAt-Date.now();return e>0?e:0}equals(e){return this.value===e.value}toString(){return this.value}toJSON(){const e={token:this.value};return void 0!==this.expiresAt&&(e.expiresAt=this.expiresAt),e}}}}),init_server_config=__esm({"internal/domain/identity/value-object/server-config.ts"(){ServerConfig=class e{constructor(e,t){__publicField(this,"apiUrl"),__publicField(this,"websiteUrl"),this.apiUrl=e,this.websiteUrl=t}static create(t,i){if(!t||"string"!=typeof t||0===t.trim().length)throw new Error("API URL cannot be empty");if(!e.isValidUrl(t))throw new Error(`Invalid API URL: ${t}`);if(i&&!e.isValidUrl(i))throw new Error(`Invalid website URL: ${i}`);return new e(t,i)}static fromJSON(t){return e.create(t.apiUrl,t.websiteUrl)}static createDefault(){return e.create("https://app.mdfriday.com","https://mdfriday.com")}static isValidUrl(e){try{return new URL(e),!0}catch{return!1}}getApiUrl(){return this.apiUrl}getWebsiteUrl(){return this.websiteUrl}withApiUrl(t){return e.create(t,this.websiteUrl)}withWebsiteUrl(t){return e.create(this.apiUrl,t)}equals(e){return this.apiUrl===e.apiUrl&&this.websiteUrl===e.websiteUrl}toJSON(){const e={apiUrl:this.apiUrl};return void 0!==this.websiteUrl&&(e.websiteUrl=this.websiteUrl),e}}}}),init_license=__esm({"internal/domain/identity/value-object/license.ts"(){License=class e{constructor(e,t,i,s,r,a=!1,n=!1){__publicField(this,"key"),__publicField(this,"plan"),__publicField(this,"expiresAt"),__publicField(this,"features"),__publicField(this,"activatedAt"),__publicField(this,"activated"),__publicField(this,"firstTime"),this.key=e,this.plan=t,this.expiresAt=i,this.features=s,this.activatedAt=r,this.activated=a,this.firstTime=n}static create(t,i,s,r,a,n,o){if(!e.isValidFormat(t))throw new Error(`Invalid license key format: ${t}`);return new e(t.toUpperCase(),i,s,r,a||Date.now(),n||!1,o||!1)}static fromJSON(t){return e.create(t.key,t.plan,t.expiresAt,t.features,t.activatedAt,t.activated,t.firstTime)}static isValidFormat(e){return/^MDF-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/i.test(e)}isExpired(){return Date.now()>this.expiresAt}isValid(){return!this.isExpired()}getDaysRemaining(){const e=this.expiresAt-Date.now();return Math.max(0,Math.ceil(e/864e5))}getEmail(){return`${this.key.replace(/^MDF-/i,"").toLowerCase()}@mdfriday.com`}getPassword(){const e=this.key.replace(/^MDF-/i,"").toLowerCase();return"undefined"!=typeof btoa?btoa(e):"undefined"!=typeof Buffer?Buffer.from(e).toString("base64"):this.manualBase64Encode(e)}manualBase64Encode(e){const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";let i="",s=0;for(;s<e.length;){const r=e.charCodeAt(s++)<<16|(s<e.length?e.charCodeAt(s++):0)<<8|(s<e.length?e.charCodeAt(s++):0);i+=t.charAt(r>>18&63),i+=t.charAt(r>>12&63),i+=s-1<e.length?t.charAt(r>>6&63):"=",i+=s<e.length?t.charAt(63&r):"="}return i}getKey(){return this.key}getMaskedKey(){const e=this.key.split("-");return 4===e.length?`MDF-••••-••••-${e[3]}`:this.key.slice(0,-4).replace(/./g,"•")+this.key.slice(-4)}getPlan(){return this.plan}getFormattedPlan(){return this.plan.charAt(0).toUpperCase()+this.plan.slice(1).toLowerCase()}getExpiresAt(){return this.expiresAt}getFormattedExpiresAt(){return new Date(this.expiresAt).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}getFeatures(){return{...this.features}}getActivatedAt(){return this.activatedAt}isActivated(){return this.activated}isFirstTime(){return this.firstTime}isTrial(){return"free"===this.plan}equals(e){return this.key===e.key}toJSON(){return{key:this.key,plan:this.plan,expiresAt:this.expiresAt,features:{...this.features},activatedAt:this.activatedAt,activated:this.activated,firstTime:this.firstTime}}toStorageFormat(){return{key:this.key,maskedKey:this.getMaskedKey(),plan:this.getFormattedPlan(),expiresAt:this.expiresAt,features:{...this.features},activatedAt:this.activatedAt,activated:this.activated,firstTime:this.firstTime,isValid:this.isValid(),daysRemaining:this.getDaysRemaining()}}}}}),init_sync_config=__esm({"internal/domain/identity/value-object/sync-config.ts"(){SyncConfig=class e{constructor(e){__publicField(this,"dbEndpoint"),__publicField(this,"dbName"),__publicField(this,"email"),__publicField(this,"dbPassword"),__publicField(this,"userDir"),__publicField(this,"status"),this.dbEndpoint=e.dbEndpoint,this.dbName=e.dbName,this.email=e.email,this.dbPassword=e.dbPassword,this.userDir=e.userDir,this.status=e.status||"active"}static create(t){if(!(t.dbEndpoint&&t.dbName&&t.email&&t.dbPassword))throw new Error("Missing required sync configuration fields");return new e(t)}static fromJSON(t){return e.create(t)}getDbEndpoint(){return this.dbEndpoint}getDbName(){return this.dbName}getEmail(){return this.email}getDbPassword(){return this.dbPassword}getUserDir(){return this.userDir}getStatus(){return this.status}isActive(){return"active"===this.status}getCouchDbUri(){return this.dbEndpoint.replace(`/${this.dbName}`,"")}toJSON(){return{dbEndpoint:this.dbEndpoint,dbName:this.dbName,email:this.email,dbPassword:this.dbPassword,userDir:this.userDir,status:this.status}}toObsidianLiveSyncFormat(){return{couchDB_URI:this.getCouchDbUri(),couchDB_DBNAME:this.dbName,couchDB_USER:this.email,couchDB_PASSWORD:this.dbPassword,encrypt:!0,syncOnStart:!0,syncOnSave:!0,liveSync:!0}}equals(e){return this.dbEndpoint===e.dbEndpoint&&this.dbName===e.dbName&&this.email===e.email}}}}),init_device=__esm({"internal/domain/identity/value-object/device.ts"(){Device=class e{constructor(e,t,i){__publicField(this,"id"),__publicField(this,"name"),__publicField(this,"type"),this.id=e,this.name=t,this.type=i}static create(t,i,s){if(!t||0===t.trim().length)throw new Error("Device ID cannot be empty");if(!i||0===i.trim().length)throw new Error("Device name cannot be empty");return new e(t,i,s)}static async createFromEnvironment(){const t=await e.generateFingerprint(),i=e.getDeviceName(),s=e.getDeviceType();return e.create(t,i,s)}static async generateFingerprint(){const e=[],t=globalThis,i=t.screen;i&&(e.push(`${i.width}x${i.height}`),e.push(`${i.colorDepth}`),e.push(`${i.pixelDepth||0}`));const s=t.navigator;s&&(e.push(s.language||""),e.push(s.platform||""),e.push(String(s.hardwareConcurrency||0)),e.push(String(s.maxTouchPoints||0)));const r=t.process;r&&r.versions&&(e.push(r.platform),e.push(r.arch),e.push(r.version));try{"undefined"!=typeof Intl&&e.push(Intl.DateTimeFormat().resolvedOptions().timeZone||"")}catch{e.push("")}if(s){const t=(s.userAgent||"").split(" ").slice(0,3).join(" ");e.push(t)}const a=e.join("|"),n=(new TextEncoder).encode(a),o=t.crypto;if(o&&o.subtle)try{const e=await o.subtle.digest("SHA-256",n);return Array.from(new Uint8Array(e)).map(e=>e.toString(16).padStart(2,"0")).join("")}catch{}let c=0;for(let e=0;e<a.length;e++)c=(c<<5)-c+a.charCodeAt(e),c&=c;return Math.abs(c).toString(16).padStart(8,"0")}static getDeviceName(){const e=globalThis,t=e.process;if(t&&t.versions){const e=t.platform;let i="Unknown OS";switch(e){case"darwin":i="macOS";break;case"win32":i="Windows";break;case"linux":i="Linux";break;default:i=e}return`Node.js on ${i}`}const i=e.navigator;if(!i)return"Unknown Device";const s=i.userAgent||"";let r="Unknown OS";s.includes("Mac")?r="macOS":s.includes("Windows")?r="Windows":s.includes("Linux")?r="Linux":s.includes("iPhone")||s.includes("iPad")?r="iOS":s.includes("Android")&&(r="Android");let a="Browser";return s.includes("Obsidian")?a="Obsidian":s.includes("Electron")&&(a="Electron"),`${a} on ${r}`}static getDeviceType(){const e=globalThis,t=e.process;if(t&&t.versions)return"desktop";const i=e.navigator;if(!i)return"desktop";const s=i.userAgent||"";return s.includes("Mobile")||s.includes("Android")||s.includes("iPhone")?"mobile":s.includes("Tablet")||s.includes("iPad")?"tablet":"desktop"}getId(){return this.id}getName(){return this.name}getType(){return this.type}equals(e){return this.id===e.id}toJSON(){return{id:this.id,name:this.name,type:this.type}}}}}),init_user=__esm({"internal/domain/identity/entity/user.ts"(){User=class{constructor(e,t,i,s=null,r=null){__publicField(this,"email"),__publicField(this,"token"),__publicField(this,"serverConfig"),__publicField(this,"license"),__publicField(this,"syncConfig"),this.email=e,this.token=t,this.serverConfig=i,this.license=s,this.syncConfig=r}getEmail(){return this.email}getToken(){return this.token}getServerConfig(){return this.serverConfig}getLicense(){return this.license}getSyncConfig(){return this.syncConfig}setToken(e){this.token=e}clearToken(){this.token=null}updateServerConfig(e){this.serverConfig=e}setLicense(e){this.license=e}clearLicense(){this.license=null}setSyncConfig(e){this.syncConfig=e}clearSyncConfig(){this.syncConfig=null}isAuthenticated(){return!!this.token&&this.token.isValid()}isTokenExpired(){return!this.token||this.token.isExpired()}hasValidLicense(){return!!this.license&&this.license.isValid()}isTrialAccount(){return!!this.license&&this.license.isTrial()}getStatus(){const e={isAuthenticated:this.isAuthenticated(),email:this.email.getValue(),serverUrl:this.serverConfig.getApiUrl(),tokenExpired:this.isTokenExpired(),hasToken:null!==this.token,hasLicense:null!==this.license,license:this.license?.getKey(),licenseValid:this.hasValidLicense(),isTrial:this.isTrialAccount(),licensePlan:this.license?.getPlan(),licenseExpires:this.license?.getFormattedExpiresAt(),licenseDaysRemaining:this.license?.getDaysRemaining(),hasSyncConfig:null!==this.syncConfig};return this.syncConfig&&(e.syncConfig={dbEndpoint:this.syncConfig.getDbEndpoint(),dbName:this.syncConfig.getDbName(),email:this.syncConfig.getEmail(),userDir:this.syncConfig.getUserDir(),status:this.syncConfig.getStatus(),isActive:this.syncConfig.isActive()}),e}toJSON(){return{email:this.email.toJSON(),token:this.token?.toJSON()||null,serverConfig:this.serverConfig.toJSON(),license:this.license?.toJSON()||null,syncConfig:this.syncConfig?.toJSON()||null}}}}}),init_user_factory=__esm({"internal/domain/identity/factory/user-factory.ts"(){init_user(),init_email(),init_token(),init_server_config(),init_license(),init_sync_config(),init_device(),init_browser_manager(),log4=getDomainLogger("user-factory",{component:"domain"}),UserFactory=class{constructor(e){__publicField(this,"httpClient"),__publicField(this,"storageProvider"),this.httpClient=e.httpClient,this.storageProvider=e.storageProvider}createAnonymous(e){const t=e||ServerConfig.createDefault(),i=Email.create("anonymous@localhost.local");return new User(i,null,t)}async load(){try{const e=await this.storageProvider.loadUserData();if(!e)return log4.debug("No user data found in storage"),null;const t=e.serverConfig||ServerConfig.createDefault(),i=e.email?Email.create(e.email):Email.create("anonymous@localhost.local"),s=new User(i,e.token,t);if(e.license&&s.setLicense(e.license),e.syncConfig){const t=SyncConfig.fromJSON(e.syncConfig);s.setSyncConfig(t)}return log4.debug("User loaded from storage",{email:i.getValue(),hasToken:!!e.token,hasLicense:!!e.license,hasSyncConfig:!!e.syncConfig}),s}catch(e){return log4.error("Failed to load user from storage",e),null}}async save(e){try{const t=await this.storageProvider.loadUserData(),i=e.getToken(),s=e.getLicense(),r=e.getSyncConfig(),a=e.getServerConfig(),n=e.getEmail().getValue(),o={...t||{},...i?{token:i}:{},...s?{license:s}:{},...r?{syncConfig:r}:{},...a?{serverConfig:a}:{},email:n};!s&&t?.license&&(o.license=t.license,log4.debug("Preserved existing license data during save")),!r&&t?.syncConfig&&(o.syncConfig=t.syncConfig,log4.debug("Preserved existing syncConfig data during save")),await this.storageProvider.saveUserData(o),log4.debug("User saved to storage (merged)",{email:n,hasToken:!!o.token,hasLicense:!!o.license,hasSyncConfig:!!o.syncConfig,preservedLicense:!s&&!!t?.license,preservedSyncConfig:!r&&!!t?.syncConfig})}catch(e){throw log4.error("Failed to save user to storage",e),e}}async loadServerConfig(){try{const e=await this.storageProvider.loadUserData();return e?.serverConfig||null}catch(e){return log4.debug("No server config found in storage"),null}}async login(e,t,i){const s=Email.create(e),r=i||ServerConfig.createDefault();log4.info("Attempting login",{email:e});try{const i=`${r.getApiUrl()}/api/login`;log4.info(`Sending login request to: ${i}`),log4.debug(`Login credentials: email=${e}, password=***`);const a=await this.httpClient.postForm(i,{email:e,password:t});if(log4.info(`Login response status: ${a.status}`),log4.debug("Login response data:",a.data),201!==a.status){const e=await a.text();throw log4.error(`Login failed with status ${a.status}: ${e}`),new Error("Invalid credentials")}log4.debug("Response structure:",JSON.stringify(a.data,null,2));const n=a.data.data[0];if(!n)throw log4.error("No token in response data:",a.data),new Error("No token received from server");log4.info(`Token received: ${n.substring(0,20)}...`);const o=Token.create(n),c=new User(s,o,r);return await this.save(c),log4.info("Login successful",{email:e}),c}catch(e){throw log4.error("Login failed",e),new Error(`Login failed: ${e.message}`)}}async register(e,t,i){const s=Email.create(e),r=i||ServerConfig.createDefault();log4.info("Attempting registration",{email:e});try{const i=await this.httpClient.postForm(`${r.getApiUrl()}/api/user`,{email:e,password:t});if(201!==i.status)throw new Error("Registration failed");const a=i.data.data[0];if(!a)throw new Error("No token received from server");const n=Token.create(a),o=new User(s,n,r);return await this.save(o),log4.info("Registration successful",{email:e}),o}catch(e){throw log4.error("Registration failed",e),new Error(`Registration failed: ${e.message}`)}}async logout(){try{await this.storageProvider.clearUserData(),log4.info("Logout successful")}catch(e){throw log4.error("Logout failed",e),new Error(`Logout failed: ${e.message}`)}}async updateServerConfig(e,t){try{let i=e.getServerConfig();t.apiUrl&&(i=i.withApiUrl(t.apiUrl)),void 0!==t.websiteUrl&&(i=i.withWebsiteUrl(t.websiteUrl)),e.updateServerConfig(i),await this.save(e),log4.info("Server config updated")}catch(e){throw log4.error("Failed to update server config",e),new Error(`Failed to update server config: ${e.message}`)}}async requestTrialLicense(e,t){const i=t||ServerConfig.createDefault();Email.create(e),log4.info("Requesting trial license",{email:e});try{const t=await this.httpClient.postMultipart(`${i.getApiUrl()}/api/license/trial`,{email:e});if(200!==t.status&&201!==t.status)throw new Error("Trial license request failed");const s=t.data;if(s&&s.data&&s.data.length>0){const e=s.data[0];return log4.info("Trial license granted",{email:e.email,licenseKey:e.license_key}),e}throw new Error("Invalid trial response format")}catch(e){throw log4.error("Failed to request trial license",e),new Error(`Trial license request failed: ${e.message}`)}}async loginWithLicense(e,t){if(!License.isValidFormat(e))throw new Error(`Invalid license key format: ${e}`);const i=License.create(e,"free",Date.now()+864e5,{},Date.now()),s=i.getEmail(),r=i.getPassword();log4.info("Logging in with license key",{licenseKey:e,email:s});const a=await this.login(s,r,t);return a._pendingLicenseKey=e,a}async activateLicense(e,t,i){if(!License.isValidFormat(t))throw new Error(`Invalid license key format: ${t}`);const s=i||await Device.createFromEnvironment();log4.info("Activating license",{licenseKey:t,deviceId:s.getId()});try{const i=e.getToken();if(!i)throw new Error("User must be logged in to activate license");const r=await this.httpClient.postMultipart(`${e.getServerConfig().getApiUrl()}/api/license/activate`,{license_key:t,device_id:s.getId(),device_name:s.getName(),device_type:s.getType()},{Authorization:`Bearer ${i.getValue()}`});if(200!==r.status&&201!==r.status)throw new Error("License activation failed");const a=r.data.data?.[0]||r.data;if(!a.success)throw new Error("License activation unsuccessful");const n={maxDevices:a.features.max_devices,maxIps:a.features.max_ips,syncEnabled:a.features.sync_enabled,syncQuota:a.features.sync_quota,publishEnabled:a.features.publish_enabled,maxSites:a.features.max_sites,maxStorage:a.features.max_storage,customDomain:a.features.custom_domain,customSubDomain:a.features.custom_sub_domain,validityDays:a.features.validity_days},o=License.create(a.license_key,a.plan,a.expires_at,n,Date.now(),a.activated,a.first_time);if(e.setLicense(o),a.sync&&a.features.sync_enabled){const t=SyncConfig.create({dbEndpoint:a.sync.db_endpoint,dbName:a.sync.db_name,email:a.sync.email,dbPassword:a.sync.db_password,userDir:a.user.user_dir,status:a.sync.status});e.setSyncConfig(t),log4.info("Sync configuration saved",{dbName:t.getDbName(),email:t.getEmail(),userDir:t.getUserDir(),status:t.getStatus(),isActive:t.isActive()})}return await this.save(e),log4.info("License activated successfully",{licenseKey:a.license_key,plan:o.getPlan(),expires:o.getFormattedExpiresAt(),activated:a.activated,firstTime:a.first_time,syncEnabled:a.features.sync_enabled,hasSyncConfig:null!==e.getSyncConfig()}),e}catch(e){throw log4.error("Failed to activate license",e),new Error(`License activation failed: ${e.message}`)}}async requestAndActivateTrial(e,t){log4.info("Starting trial flow",{email:e});try{const i=await this.requestTrialLicense(e,t),s=await this.loginWithLicense(i.license_key,t);return await this.activateLicense(s,i.license_key),log4.info("Trial flow completed successfully",{email:e,licenseKey:i.license_key}),s}catch(e){throw log4.error("Trial flow failed",e),new Error(`Trial flow failed: ${e.message}`)}}async refreshTokenIfNeeded(e){const t=e.getToken(),i=e.getLicense();if(!t)return log4.debug("No token to refresh"),e;if(t.isValid()&&!t.isExpired())return log4.debug("Token is still valid, no refresh needed"),e;if(log4.info("Token expired or expiring soon, attempting auto-refresh"),i)try{const t=i.getKey(),s=e.getServerConfig();log4.info("Refreshing token using license",{licenseKey:t});const r=await this.loginWithLicense(t,s);return r.setLicense(i),await this.save(r),log4.info("Token refreshed successfully using license"),r}catch(e){throw log4.error("Failed to refresh token with license",e),new Error(`Failed to refresh token: ${e.message}`)}throw log4.warn("Token expired but no license available for auto-refresh"),new Error("Token expired and cannot be auto-refreshed (no license available)")}async requestWithAutoRefresh(e,t){const i=e.getToken();if(!i)throw new Error("User is not authenticated");try{return await t(i.getValue())}catch(i){const s=i?.message||i?.toString?.()||String(i);if(s.includes("401")||s.includes("Unauthorized")||i?.status&&401===i.status){log4.info("Received 401 error, attempting token refresh");try{const i=(await this.refreshTokenIfNeeded(e)).getToken();if(!i)throw new Error("Failed to refresh token - no token returned");return log4.info("Token refreshed, retrying request"),await t(i.getValue())}catch(e){throw log4.error("Failed to refresh token and retry request",e),new Error(`Request failed with 401, and token refresh failed: ${e.message}`)}}throw i}}async getLicenseUsage(e){const t=e.getLicense();if(!t)throw new Error("No license found for user");const i=t.getKey(),s=e.getServerConfig();return log4.info("Getting license usage",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=Date.now(),r=`${s.getApiUrl()}/api/license/usage?key=${i}&_t=${t}`,a=await this.httpClient.get(r,{Authorization:`Bearer ${e}`,"Cache-Control":"no-cache",Pragma:"no-cache"});if(200!==a.status){const e=await a.text();throw log4.error("License usage fetch failed",{status:a.status,text:e}),new Error(`License usage fetch failed: ${a.status}`)}const n=a.data;if(n&&n.data&&n.data.length>0)return n.data[0];throw new Error("Invalid usage response format")})}async getLicenseInfo(e,t){let i=t;if(!i){const t=e.getLicense();if(!t)throw new Error("No license found for user and no license key provided");i=t.getKey()}const s=e.getServerConfig();return log4.info("Getting license info",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=Date.now(),r=`${s.getApiUrl()}/api/license/info?key=${i}&_t=${t}`,a=await this.httpClient.get(r,{Authorization:`Bearer ${e}`,"Cache-Control":"no-cache",Pragma:"no-cache"});if(200!==a.status){const e=await a.text();throw log4.error("License info fetch failed",{status:a.status,text:e}),new Error(`License info fetch failed: ${a.status}`)}const n=a.data;if(n&&n.data&&n.data.length>0)return n.data[0];throw new Error("Invalid license info response format")})}async resetUsage(e){const t=e.getLicense();if(!t)throw new Error("No license found for user");const i=t.getKey(),s=e.getServerConfig();return log4.info("Resetting license usage",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=`${s.getApiUrl()}/api/license/usage/reset?key=${i}`,r=await this.httpClient.post(t,{},{Authorization:`Bearer ${e}`});if(200!==r.status&&201!==r.status){const e=await r.text();throw log4.error("License usage reset failed",{status:r.status,text:e}),new Error(`Reset failed: ${r.status}`)}return{success:!0}})}async getDomains(e){const t=e.getLicense();if(!t)throw new Error("No license found for user");const i=t.getKey(),s=e.getServerConfig();return log4.info("Getting domains",{licenseKey:i}),this.requestWithAutoRefresh(e,async e=>{const t=`${s.getApiUrl()}/api/license/domains?key=${i}`,r=await this.httpClient.get(t,{Authorization:`Bearer ${e}`});if(200!==r.status){const e=await r.text();return log4.error("Get domains failed",{status:r.status,text:e}),null}const a=r.data;return a&&a.data&&a.data.length>0?a.data[0]:null})}async checkSubdomainAvailability(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Checking subdomain availability",{licenseKey:s,subdomain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/subdomain/check`,a=await this.httpClient.postMultipart(i,{license_key:s,subdomain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Check subdomain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async updateSubdomain(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Updating subdomain",{licenseKey:s,newSubdomain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/subdomain/update`,a=await this.httpClient.postMultipart(i,{license_key:s,new_subdomain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Update subdomain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async checkCustomDomain(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Checking custom domain",{licenseKey:s,domain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/domain/check`,a=await this.httpClient.postMultipart(i,{license_key:s,domain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Check custom domain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async addCustomDomain(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Adding custom domain",{licenseKey:s,domain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/domain/add`,a=await this.httpClient.postMultipart(i,{license_key:s,domain:t},{Authorization:`Bearer ${e}`});if(200!==a.status&&201!==a.status){const e=await a.text();return log4.error("Add custom domain failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}async checkCustomDomainHttpsStatus(e,t){const i=e.getLicense();if(!i)throw new Error("No license found for user");const s=i.getKey(),r=e.getServerConfig();return log4.info("Checking HTTPS status",{licenseKey:s,domain:t}),this.requestWithAutoRefresh(e,async e=>{const i=`${r.getApiUrl()}/api/license/domain/https-status`,a=await this.httpClient.postMultipart(i,{license_key:s,domain:t},{Authorization:`Bearer ${e}`});if(200!==a.status){const e=await a.text();return log4.error("Check HTTPS status failed",{status:a.status,text:e}),null}const n=a.data;return n&&n.data&&n.data.length>0?n.data[0]:null})}}}}),init_type=__esm({"internal/domain/identity/type.ts"(){}}),identity_exports={};__export(identity_exports,{Device:()=>Device,Email:()=>Email,License:()=>License,ServerConfig:()=>ServerConfig,SyncConfig:()=>SyncConfig,Token:()=>Token,User:()=>User,UserFactory:()=>UserFactory});var ProjectMetadata,init_identity=__esm({"internal/domain/identity/index.ts"(){init_email(),init_token(),init_server_config(),init_license(),init_sync_config(),init_device(),init_user(),init_user_factory(),init_type()}}),project_metadata_exports={};__export(project_metadata_exports,{ProjectMetadata:()=>ProjectMetadata});var mod,init_project_metadata=__esm({"internal/domain/workspace/value-object/project-metadata.ts"(){ProjectMetadata=class e{constructor(e){__publicField(this,"id"),__publicField(this,"name"),__publicField(this,"workspaceId"),__publicField(this,"createdAt"),__publicField(this,"updatedAt"),__publicField(this,"buildHistory"),__publicField(this,"previews"),__publicField(this,"contentLinks"),__publicField(this,"staticLink"),__publicField(this,"fileLink"),__publicField(this,"baseURLStructure"),this.id=e.id,this.name=e.name,this.workspaceId=e.workspaceId||"",this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this.buildHistory=e.buildHistory||[],this.previews=e.previews||{},this.contentLinks=e.contentLinks||[],this.staticLink=e.staticLink||null,this.fileLink=e.fileLink||null,this.baseURLStructure=e.baseURLStructure||null}static create(t){if(!t.id||!t.name)throw new Error("Project ID and name are required");return new e(t)}update(t){return new e({...this,...t,updatedAt:Date.now()})}toJSON(){const e={id:this.id,name:this.name,createdAt:this.createdAt,updatedAt:this.updatedAt};return this.workspaceId&&(e.workspaceId=this.workspaceId),this.buildHistory&&this.buildHistory.length>0&&(e.buildHistory=this.buildHistory),this.previews&&Object.keys(this.previews).length>0&&(e.previews=this.previews),this.contentLinks&&this.contentLinks.length>0&&(e.contentLinks=this.contentLinks),this.staticLink&&(e.staticLink=this.staticLink),this.fileLink&&(e.fileLink=this.fileLink),this.baseURLStructure&&(e.baseURLStructure=this.baseURLStructure),e}}}}),mobile_exports={};__export(mobile_exports,{createObsidianAuthService:()=>createObsidianAuthService,createObsidianGlobalConfigService:()=>createObsidianGlobalConfigService,createObsidianIdentityService:()=>createObsidianIdentityService,createObsidianLicenseService:()=>createObsidianLicenseService,createObsidianWorkspaceAppService:()=>createObsidianWorkspaceAppService,createObsidianWorkspaceService:()=>createObsidianWorkspaceService}),module.exports=(mod=mobile_exports,((e,t,i,s)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let i of __getOwnPropNames(t))__hasOwnProp.call(e,i)||void 0===i||__defProp(e,i,{get:()=>t[i],enumerable:!(s=__getOwnPropDesc(t,i))||s.enumerable});return e})(__defProp({},"__esModule",{value:!0}),mod));var ObsidianAuthService=class{constructor(e,t){this.httpClient=e,this.identityAdapter=t}async getStatus(e){try{const t=await this.identityAdapter.getIdentityService(e,this.httpClient),i=t.getStatus(),s={isAuthenticated:i.isAuthenticated,serverUrl:i.serverUrl,hasSyncConfig:i.hasSyncConfig,...i.license?{license:i.license}:{},...i.email?{email:i.email}:{}};if(i.isAuthenticated){const e=t.getToken();e&&(s.token=e)}return i.syncConfig&&(s.syncConfig={dbEndpoint:i.syncConfig.dbEndpoint,dbName:i.syncConfig.dbName,email:i.syncConfig.email,userDir:i.syncConfig.userDir,status:i.syncConfig.status,isActive:i.syncConfig.isActive}),{success:!0,message:i.isAuthenticated?`Authenticated as ${i.email}`:"Not authenticated",data:s}}catch(e){const t=e.message;return t.includes("No workspace found")?{success:!1,message:"No workspace found. Please initialize workspace first.",error:t}:{success:!1,message:`Failed to get status: ${t}`,error:t}}}async getConfig(e){try{const t=(await this.identityAdapter.getIdentityService(e,this.httpClient)).getServerConfig(),i=t.getWebsiteUrl(),s={apiUrl:t.getApiUrl()};return i&&(s.websiteUrl=i),{success:!0,message:"Server configuration retrieved",data:s}}catch(e){const t=e.message;return t.includes("No workspace found")?{success:!1,message:"No workspace found. Please initialize workspace first.",error:t}:{success:!1,message:`Failed to get config: ${t}`,error:t}}}async updateConfig(e,t){try{const i={};t.apiUrl&&(i.apiUrl=t.apiUrl),t.websiteUrl&&(i.websiteUrl=t.websiteUrl);const s=await this.identityAdapter.getIdentityService(e,this.httpClient);await s.updateServerConfig(i);const r=s.getServerConfig(),a=r.getWebsiteUrl(),n={apiUrl:r.getApiUrl()};return a&&(n.websiteUrl=a),{success:!0,message:"Server configuration updated",data:n}}catch(e){const t=e.message;return t.includes("No workspace found")?{success:!1,message:"No workspace found. Please initialize workspace first.",error:t}:{success:!1,message:`Failed to update config: ${t}`,error:t}}}};init_browser_manager();var log=getDomainLogger("obsidian-license",{component:"interface"}),ObsidianLicenseService=class{constructor(e,t){this.httpClient=e,this.identityAdapter=t}async requestTrial(e,t){try{if(!t)return{success:!1,error:"Email is required"};log.info("Requesting trial license (without activation)",{email:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.requestTrial(t);return{success:!0,message:"Trial license requested successfully",data:{email:s.email,licenseKey:s.license_key,password:s.password,validityDays:s.validity_days}}}catch(e){return log.error("Trial license request failed",e),{success:!1,error:e.message}}}async requestAndActivateTrial(e,t){try{if(!t)return{success:!1,error:"Email is required"};log.info("Requesting and activating trial license",{email:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=(await i.requestAndActivateTrial(t)).getLicense();return s?{success:!0,message:"Trial license activated successfully",data:this.buildLicenseInfo(s)}:{success:!1,error:"Trial license request succeeded but license not found"}}catch(e){return log.error("Trial license request and activation failed",e),{success:!1,error:e.message}}}async loginWithLicense(e,t){try{if(!t)return{success:!1,error:"License key is required"};log.info("Logging in with license key",{licenseKey:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.loginWithLicense(t);return log.info("Login successful",{email:s.getEmail().getValue(),hasToken:!!s.getToken()}),{success:!0,message:"Logged in successfully. Token saved.",data:{}}}catch(e){return log.error("License login failed",e),{success:!1,error:e.message}}}async activateLicense(e,t){try{if(!t)return{success:!1,error:"License key is required"};log.info("Activating license",{licenseKey:t});const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.activateLicense(t),r=s.getLicense(),a=s.getSyncConfig();if(!r)return{success:!1,error:"License activation succeeded but license not found"};const n=this.buildLicenseInfo(r);return n.user={email:s.getEmail().getValue(),userDir:a?.getUserDir()||""},n.activation={activated:r.isActivated(),firstTime:r.isFirstTime()},a&&r.getFeatures().syncEnabled&&(n.sync={enabled:!0,status:a.getStatus(),dbEndpoint:a.getDbEndpoint(),dbName:a.getDbName(),email:a.getEmail(),dbPassword:a.getDbPassword(),userDir:a.getUserDir(),liveSyncConfig:a.toObsidianLiveSyncFormat()},log.info("Sync configuration included in activation response",{dbName:a.getDbName(),email:a.getEmail(),status:a.getStatus()})),{success:!0,message:"License activated successfully",data:n}}catch(e){return log.error("License activation failed",e),{success:!1,error:e.message}}}async getLicenseInfo(e){try{const t=await this.identityAdapter.getIdentityService(e,this.httpClient),i=t.getLicense();if(!i)return{success:!0,message:"No active license"};const s=this.buildLicenseInfo(i),r=t.getCurrentUser();if(r){const e=r.getSyncConfig();s.user={email:r.getEmail().getValue(),userDir:e?.getUserDir()||""}}return{success:!0,data:s}}catch(e){return log.error("Failed to get license info",e),{success:!1,error:e.message}}}async getLicenseUsage(e){try{const t=await this.identityAdapter.getIdentityService(e,this.httpClient),i=await t.getLicenseUsage();return i?{success:!0,data:{licenseKey:i.license_key,plan:i.plan,devices:{count:i.devices.count,max:i.features.max_devices,list:i.devices.devices.map(e=>({id:e.id,name:e.device_name,type:e.device_type,status:e.status,lastSeenAt:e.last_seen_at}))},ips:{count:i.ips.count,max:i.features.max_ips,list:i.ips.ips.map(e=>({ip:e.ip_address,city:e.city,region:e.region,country:e.country,status:e.status,lastSeenAt:e.last_seen_at}))},disk:{syncUsage:Number(i.disks.sync_disk_usage)||0,publishUsage:Number(i.disks.publish_disk_usage)||0,totalUsage:Number(i.disks.total_disk_usage)||0,maxStorage:i.features.max_storage,unit:i.disks.unit}}}:{success:!1,error:"Failed to get license usage information"}}catch(e){return log.error("Failed to get license usage",e),{success:!1,error:e.message}}}async resetUsage(e,t){try{if(!t)return{success:!1,error:"This will delete all sync and publish data! Set force=true to confirm."};const i=await this.identityAdapter.getIdentityService(e,this.httpClient),s=await i.resetUsage();return s.success?{success:!0,message:"License usage data has been reset successfully",data:s}:{success:!1,error:s.message||"Unknown error"}}catch(e){return log.error("Failed to reset license usage",e),{success:!1,error:e.message}}}async hasActiveLicense(e){try{const t=await this.getLicenseInfo(e);return t.success&&void 0!==t.data&&!t.data.isExpired}catch{return!1}}buildLicenseInfo(e){const t=e.getFeatures();return{key:e.getKey(),plan:e.getFormattedPlan(),isExpired:e.isExpired(),expires:e.getFormattedExpiresAt(),expiresAt:e.getExpiresAt(),daysRemaining:e.getDaysRemaining(),isTrial:e.isTrial(),features:{maxDevices:t.maxDevices,maxIps:t.maxIps,syncEnabled:t.syncEnabled,syncQuota:t.syncQuota,publishEnabled:t.publishEnabled,maxSites:t.maxSites,maxStorage:t.maxStorage,customDomain:t.customDomain,customSubDomain:t.customSubDomain}}}};init_browser_manager();var log2=getDomainLogger("obsidian-workspace",{component:"interface"}),ObsidianWorkspaceService=class{constructor(e){this.workspaceAdapter=e}buildWorkspaceInfo(e){const t=e.getInfo(),i=e.getProjects();return{id:t.id,name:t.name,path:t.path,createdAt:t.createdAt.toISOString(),modulesDir:t.modulesDir,projectsDir:t.projectsDir,projectCount:t.projectCount,projects:i.map(e=>{const t=e.getMetadata(),i=t.buildHistory||[],s=i.length>0?new Date(i[i.length-1].timestamp).toISOString():void 0,r={id:t.id,name:t.name,path:e.getPath(),createdAt:new Date(t.createdAt).toISOString()};return s&&(r.lastBuild=s),r})}}async initWorkspace(e,t={}){try{log2.info("Initializing workspace from Obsidian",{workspacePath:e,options:t});const i=this.workspaceAdapter.getWorkspaceAppService(),s={};t.name&&(s.name=t.name),t.modulesDir&&(s.modulesDir=t.modulesDir),t.projectsDir&&(s.projectsDir=t.projectsDir);const r=await i.createWorkspace(e,s),a=this.buildWorkspaceInfo(r);return log2.info("Workspace initialized successfully",{workspaceId:a.id,name:a.name,projectCount:a.projects.length}),{success:!0,message:`Workspace initialized: ${a.name}`,data:a}}catch(e){return log2.error("Failed to initialize workspace",e),{success:!1,message:"Failed to initialize workspace",error:e.message}}}async getWorkspaceInfo(e){try{log2.info("Getting workspace info from Obsidian",{workspacePath:e});const t=this.workspaceAdapter.getWorkspaceAppService(),i=await t.loadWorkspace(e),s=this.buildWorkspaceInfo(i);return log2.info("Workspace info retrieved",{workspaceId:s.id,name:s.name,projectCount:s.projects.length}),{success:!0,data:s}}catch(e){return log2.error("Failed to get workspace info",e),{success:!1,message:"Failed to get workspace info",error:e.message}}}async workspaceExists(e){try{log2.debug("Checking workspace existence",{workspacePath:e});const t=this.workspaceAdapter.getFileSystemRepository(),i=this.workspaceAdapter.getWorkspaceFactory(),s=await t.resolvePath(e);return{success:!0,data:await i.isWorkspace(s)}}catch(e){return log2.error("Failed to check workspace existence",e),{success:!1,error:e.message,data:!1}}}};init_browser_manager();var log3=getDomainLogger("obsidian-config",{component:"interface"}),ObsidianGlobalConfigService=class{constructor(e){this.workspaceAdapter=e}async get(e,t){try{log3.info("Getting global config",{workspacePath:e,key:t});const i=this.workspaceAdapter.getWorkspaceAppService(),s=await i.loadWorkspace(e),r=await s.getConfig(t);return void 0===r?{success:!1,error:`Configuration key not found: ${t}`}:{success:!0,data:{key:t,value:r}}}catch(e){return log3.error("Failed to get global config",e),{success:!1,error:e.message}}}async set(e,t,i){try{log3.info("Setting global config",{workspacePath:e,key:t});const s=this.workspaceAdapter.getWorkspaceAppService(),r=await s.loadWorkspace(e);return await r.setConfig(t,i),await s.saveWorkspace(r),{success:!0,message:`Configuration updated: ${t}`,data:{key:t,value:i}}}catch(e){return log3.error("Failed to set global config",e),{success:!1,error:e.message}}}async list(e){try{log3.info("Listing global config",{workspacePath:e});const t=this.workspaceAdapter.getWorkspaceAppService(),i=await t.loadWorkspace(e);return{success:!0,data:{config:await i.getAllConfig(),scope:"global"}}}catch(e){return log3.error("Failed to list global config",e),{success:!1,error:e.message}}}async unset(e,t){try{log3.info("Unsetting global config",{workspacePath:e,key:t});const i=this.workspaceAdapter.getWorkspaceAppService(),s=await i.loadWorkspace(e);return await s.unsetConfig(t)?(await i.saveWorkspace(s),{success:!0,message:`Configuration deleted: ${t}`,data:{key:t}}):{success:!1,error:`Configuration key not found: ${t}`}}catch(e){return log3.error("Failed to unset global config",e),{success:!1,error:e.message}}}async getConfigPath(e){try{const t=this.workspaceAdapter.getWorkspaceAppService();return{success:!0,data:{path:(await t.loadWorkspace(e)).getConfigPath()}}}catch(e){return log3.error("Failed to get global config path",e),{success:!1,error:e.message}}}};init_server_config(),init_browser_manager();var log5=getDomainLogger("identity-app",{component:"application"}),IdentityAppService=class{constructor(e){__publicField(this,"userFactory"),__publicField(this,"currentUser",null),__publicField(this,"cachedServerConfig",null),this.userFactory=e.userFactory}async initialize(){try{this.currentUser=await this.userFactory.load(),this.currentUser?this.cachedServerConfig=this.currentUser.getServerConfig():log5.debug("No existing user session")}catch(e){log5.error("Failed to initialize identity service",e)}}async login(e,t){const i=await this.userFactory.login(e,t,this.cachedServerConfig||void 0);return this.currentUser=i,this.cachedServerConfig=i.getServerConfig(),i}async register(e,t){const i=await this.userFactory.register(e,t,this.cachedServerConfig||void 0);return this.currentUser=i,this.cachedServerConfig=i.getServerConfig(),i}async logout(){await this.userFactory.logout(),this.currentUser=null}getCurrentUser(){return this.currentUser}isAuthenticated(){return this.currentUser?.isAuthenticated()||!1}getToken(){return this.currentUser?.getToken()?.getValue()||null}getStatus(){return this.currentUser?this.currentUser.getStatus():{isAuthenticated:!1,email:"",serverUrl:this.getServerConfig().getApiUrl(),tokenExpired:!0,hasToken:!1,hasLicense:!1,license:void 0,licenseValid:!1,isTrial:!1,licensePlan:void 0,licenseExpires:void 0,licenseDaysRemaining:void 0,hasSyncConfig:!1,syncConfig:void 0}}getServerConfig(){return this.currentUser?this.currentUser.getServerConfig():this.cachedServerConfig||ServerConfig.createDefault()}async updateServerConfig(e){this.currentUser||(this.currentUser=this.userFactory.createAnonymous()),await this.userFactory.updateServerConfig(this.currentUser,e),this.cachedServerConfig=this.currentUser.getServerConfig()}async requestTrial(e){return this.userFactory.requestTrialLicense(e,this.cachedServerConfig||void 0)}async loginWithLicense(e){const t=await this.userFactory.loginWithLicense(e,this.cachedServerConfig||void 0);return this.currentUser=t,this.cachedServerConfig=t.getServerConfig(),t}async activateLicense(e,t){if(!this.currentUser)throw new Error("User must be logged in to activate license");const i=await this.userFactory.activateLicense(this.currentUser,e,t);return this.currentUser=i,i}async requestAndActivateTrial(e){const t=await this.userFactory.requestAndActivateTrial(e,this.cachedServerConfig||void 0);return this.currentUser=t,this.cachedServerConfig=t.getServerConfig(),t}getLicense(){return this.currentUser?.getLicense()||null}hasValidLicense(){return this.currentUser?.hasValidLicense()||!1}isTrialAccount(){return this.currentUser?.isTrialAccount()||!1}getLicenseDisplay(){const e=this.getLicense();return e?{key:e.getMaskedKey(),plan:e.getFormattedPlan(),expires:e.getFormattedExpiresAt(),daysRemaining:e.getDaysRemaining(),isValid:e.isValid(),isExpired:e.isExpired(),isTrial:e.isTrial(),features:e.getFeatures()}:null}async refreshTokenIfNeeded(){if(!this.currentUser)return log5.debug("No current user, cannot refresh token"),!1;const e=this.currentUser.getToken(),t=await this.userFactory.refreshTokenIfNeeded(this.currentUser),i=t.getToken(),s=e?.getValue()!==i?.getValue();return s&&(this.currentUser=t,log5.info("Token was refreshed")),s}async requestWithAutoRefresh(e){if(!this.currentUser)throw new Error("User must be logged in to make authenticated requests");const t=await this.userFactory.requestWithAutoRefresh(this.currentUser,e),i=await this.userFactory.load();return i&&(this.currentUser=i),t}async getLicenseUsage(){if(!this.currentUser)throw new Error("User must be logged in to get license usage");return this.userFactory.getLicenseUsage(this.currentUser)}async getLicenseInfo(e){if(!this.currentUser)throw new Error("User must be logged in to get license info");return this.userFactory.getLicenseInfo(this.currentUser,e)}async resetUsage(){if(!this.currentUser)throw new Error("User must be logged in to reset usage");return this.userFactory.resetUsage(this.currentUser)}async getDomains(){if(!this.currentUser)throw new Error("User must be logged in to get domains");return this.userFactory.getDomains(this.currentUser)}async checkSubdomainAvailability(e){if(!this.currentUser)throw new Error("User must be logged in to check subdomain");return this.userFactory.checkSubdomainAvailability(this.currentUser,e)}async updateSubdomain(e){if(!this.currentUser)throw new Error("User must be logged in to update subdomain");return this.userFactory.updateSubdomain(this.currentUser,e)}async checkCustomDomain(e){if(!this.currentUser)throw new Error("User must be logged in to check custom domain");return this.userFactory.checkCustomDomain(this.currentUser,e)}async addCustomDomain(e){if(!this.currentUser)throw new Error("User must be logged in to add custom domain");return this.userFactory.addCustomDomain(this.currentUser,e)}async checkCustomDomainHttpsStatus(e){if(!this.currentUser)throw new Error("User must be logged in to check HTTPS status");return this.userFactory.checkCustomDomainHttpsStatus(this.currentUser,e)}};init_browser_manager();var log6=getDomainLogger("workspace-app",{component:"application"}),WorkspaceAppService=class{constructor(e){__publicField(this,"workspaceFactory"),this.workspaceFactory=e.workspaceFactory}async loadWorkspace(e){return e?this.workspaceFactory.load(e):this.workspaceFactory.loadOrFind()}async createWorkspace(e,t){return this.workspaceFactory.create(e,t)}async saveWorkspace(e){return this.workspaceFactory.save(e)}async findWorkspaceRoot(e){return this.workspaceFactory.findWorkspaceRoot(e||process.cwd())}async createProject(e,t,i){return this.workspaceFactory.createProject(e,t,i)}async createProjectFromFolder(e,t,i,s){return this.workspaceFactory.createProjectFromFolder(e,t,i,s)}async createProjectFromFile(e,t,i,s){return this.workspaceFactory.createProjectFromFile(e,t,i,s)}async deleteProject(e,t,i){return this.workspaceFactory.deleteProject(e,t,i)}async loadWorkspaceAndProject(e,t){const i=await this.loadWorkspace(t);let s;if(e){if(s=i.findProject(e),!s){const t=i.getProjects(),r=this.workspaceFactory.fileSystemRepo;if(r){const i=r.resolvePathSync(e);for(const e of t){const t=e.getPath();if(i.startsWith(t)||t===i){s=e;break}try{const a=await r.resolvePath(i),n=await r.resolvePath(t);if(a.startsWith(n)||n===a){s=e;break}}catch(e){}}}else s=void 0;if(!s)throw new Error(`Project not found: ${e}`)}}else{const e=process.cwd(),t=i.getProjects(),r=this.workspaceFactory.fileSystemRepo;if(r)for(const i of t){const t=i.getPath();if(e.startsWith(t)){s=i;break}try{const a=await r.resolvePath(e),n=await r.resolvePath(t);if(a.startsWith(n)){s=i;break}}catch(e){}}if(s||1!==t.length||(s=t[0]),!s){if(0===t.length)throw new Error("No projects found in workspace");throw new Error(`Project not found in current directory: ${e}\nPlease specify a project name with --project <name>`)}}return log6.debug("Loaded workspace and project",{workspaceId:i.getId(),projectId:s.getId(),projectName:s.getName()}),{workspace:i,project:s}}async createSnapshot(e,t){return this.workspaceFactory.createSnapshot(e,t)}async listSnapshots(e){return this.workspaceFactory.listSnapshots(e)}async restoreSnapshot(e,t,i){return this.workspaceFactory.restoreSnapshot(e,t,i)}async deleteSnapshot(e,t){return this.workspaceFactory.deleteSnapshot(e,t)}async getSnapshot(e,t){return this.workspaceFactory.getSnapshot(e,t)}async loadProject(e){return this.workspaceFactory.loadProject(e)}async saveProject(e){return this.workspaceFactory.saveProject(e)}async findProjectRoot(e){return this.workspaceFactory.findProjectRoot(e)}async scanFolderStructure(e){return this.workspaceFactory.scanFolderStructure(e)}createIdentityStorage(e){return this.workspaceFactory.createIdentityStorage(e)}async setupProjectBaseURLStructure(e){return this.workspaceFactory.setupBaseURLStructure(e)}async cleanProjectBaseURLStructure(e){return this.workspaceFactory.cleanBaseURLStructure(e)}async ensureProjectBaseURLStructure(e){return this.workspaceFactory.ensureBaseURLStructure(e)}},WorkspaceMetadata=class e{constructor(e){__publicField(this,"version"),__publicField(this,"id"),__publicField(this,"name"),__publicField(this,"createdAt"),__publicField(this,"updatedAt"),__publicField(this,"paths"),__publicField(this,"defaults"),this.version=e.version,this.id=e.id,this.name=e.name,this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this.paths={...e.paths},this.defaults=e.defaults?{...e.defaults}:{}}static create(t){if(!t.id||!t.name)throw new Error("Workspace ID and name are required");return new e(t)}update(t){return new e({...this,...t,updatedAt:Date.now()})}toJSON(){const e={version:this.version,id:this.id,name:this.name,createdAt:this.createdAt,updatedAt:this.updatedAt,paths:{...this.paths}};return this.defaults&&Object.keys(this.defaults).length>0&&(e.defaults={...this.defaults}),e}},FolderStructure=class e{constructor(e,t,i,s){__publicField(this,"rootPath"),__publicField(this,"contentFolders"),__publicField(this,"staticFolder"),__publicField(this,"isStructured"),this.rootPath=e,this.contentFolders=t,this.staticFolder=i,this.isStructured=s}static fromScanResult(t){return new e(t.rootPath,t.contentFolders,t.staticFolder,t.isStructured)}static createEmpty(t){return new e(t,[],null,!1)}static createSingleContent(t,i,s="en"){return new e(t,[{path:i,languageCode:s,weight:0}],null,!0)}getRootPath(){return this.rootPath}getContentFolders(){return[...this.contentFolders]}getStaticFolder(){return this.staticFolder?{...this.staticFolder}:null}getIsStructured(){return this.isStructured}hasContentFolders(){return this.contentFolders.length>0}hasStaticFolder(){return null!==this.staticFolder}getContentFolderCount(){return this.contentFolders.length}getDefaultContentFolder(){return this.contentFolders.find(e=>0===e.weight)||null}getLanguageContentFolders(){return this.contentFolders.filter(e=>e.weight>0)}getContentFolderByLanguage(e){return this.contentFolders.find(t=>t.languageCode===e)||null}getSupportedLanguages(){return this.contentFolders.map(e=>e.languageCode)}isValid(){return!this.isStructured||this.contentFolders.length>0}isMultilingual(){return this.contentFolders.length>1}getSummary(){if(!this.isStructured)return`Empty structure at ${this.rootPath}`;const e=[];if(e.push(`Structured folder at ${this.rootPath}:`),e.push(` - ${this.contentFolders.length} content folder(s)`),this.isMultilingual()){const t=this.getSupportedLanguages().join(", ");e.push(` Languages: ${t}`)}return this.staticFolder&&e.push(" - static folder"),e.join("\n")}toJSON(){return{rootPath:this.rootPath,contentFolders:this.contentFolders,staticFolder:this.staticFolder,isStructured:this.isStructured}}static fromJSON(t){return e.fromScanResult(t)}};init_browser_manager();var log7=getDomainLogger("workspace",{component:"domain"}),Workspace2=class{constructor(e,t,i,s,r){if(__publicField(this,"rootPath"),__publicField(this,"metadata"),__publicField(this,"projects"),__publicField(this,"authentication"),__publicField(this,"fileSystemRepo"),this.rootPath=e,this.metadata=t,this.projects=i,this.authentication=s,this.fileSystemRepo=r,!this.fileSystemRepo)throw new Error("FileSystemRepository is required for Workspace")}getPath(){return this.rootPath}getMetadata(){return this.metadata}getId(){return this.metadata.id}getName(){return this.metadata.name}getModulesDir(){return this.fileSystemRepo.join(this.rootPath,this.metadata.paths.modules)}getProjectsDir(){return this.fileSystemRepo.join(this.rootPath,this.metadata.paths.projects)}updateMetadata(e){this.metadata=this.metadata.update(e),log7.debug("Workspace metadata updated",{workspaceId:this.getId()})}updateName(e){this.updateMetadata({name:e})}getProjects(){return Array.from(this.projects.values())}getProject(e){return this.projects.get(e)}getProjectByName(e){for(const t of this.projects.values())if(t.getName()===e)return t}findProject(e){return this.getProject(e)||this.getProjectByName(e)}hasProject(e){return this.projects.has(e)}addProject(e){if(this.projects.has(e.getId()))throw new Error(`Project ${e.getId()} already exists in workspace`);this.projects.set(e.getId(),e),log7.info(`Project added to workspace: ${e.getName()} (${e.getId()})`)}removeProject(e){const t=this.projects.get(e);return t?(this.projects.delete(e),log7.info(`Project removed from workspace: ${t.getName()} (${e})`),t):null}getProjectCount(){return this.projects.size}getProjectRegistry(){const e=[];for(const t of this.projects.values()){const i=t.getMetadata(),s=t.getPath(),r=this.fileSystemRepo.relative(this.getProjectsDir(),s);e.push({id:i.id,name:i.name,path:r,absolutePath:s,createdAt:i.createdAt,updatedAt:i.updatedAt,status:"active"})}return{version:"1.0",projects:e}}getAuthentication(){return this.authentication}hasAuthentication(){return this.authentication.hasAuth()}getConfigPath(){return this.fileSystemRepo.join(this.rootPath,".mdfriday","config.json")}async getConfig(e){const t=this.getConfigPath();try{const i=await this.fileSystemRepo.readFile(t,"utf-8"),s=JSON.parse(i);return this.getNestedValue(s,e)}catch(e){if(e.message?.includes("Cannot access path"))return;throw e}}async getAllConfig(){const e=this.getConfigPath();try{const t=await this.fileSystemRepo.readFile(e,"utf-8");return JSON.parse(t)}catch(e){if(e.message?.includes("Cannot access path"))return{};throw e}}async setConfig(e,t){const i=this.getConfigPath(),s=this.fileSystemRepo.dirname(i);await this.fileSystemRepo.createDirectory(s,!0);let r={};try{const e=await this.fileSystemRepo.readFile(i,"utf-8");r=JSON.parse(e)}catch(e){if(!e.message?.includes("Cannot access path"))throw e}this.setNestedValue(r,e,t),await this.fileSystemRepo.writeFile(i,JSON.stringify(r,null,2),"utf-8"),log7.debug(`Workspace config updated: ${e}`,{workspaceId:this.getId()})}async unsetConfig(e){const t=this.getConfigPath();try{const i=await this.fileSystemRepo.readFile(t,"utf-8"),s=JSON.parse(i),r=this.deleteNestedValue(s,e);return r&&(await this.fileSystemRepo.writeFile(t,JSON.stringify(s,null,2),"utf-8"),log7.debug(`Workspace config deleted: ${e}`,{workspaceId:this.getId()})),r}catch(e){if(e.message?.includes("Cannot access path"))return!1;throw e}}getNestedValue(e,t){const i=t.split(".");let s=e;for(const e of i){if(null==s||"object"!=typeof s)return;s=s[e]}return s}setNestedValue(e,t,i){const s=t.split(".");let r=e;for(let e=0;e<s.length-1;e++){const t=s[e];t in r&&"object"==typeof r[t]||(r[t]={}),r=r[t]}r[s[s.length-1]]=i}deleteNestedValue(e,t){const i=t.split(".");let s=e;for(let e=0;e<i.length-1;e++){const t=i[e];if(!(t in s)||"object"!=typeof s[t])return!1;s=s[t]}const r=i[i.length-1];return r in s&&(delete s[r],!0)}getInfo(){return{id:this.metadata.id,name:this.metadata.name,path:this.rootPath,createdAt:new Date(this.metadata.createdAt),updatedAt:new Date(this.metadata.updatedAt),modulesDir:this.metadata.paths.modules,projectsDir:this.metadata.paths.projects,projectCount:this.projects.size,hasAuth:this.authentication.hasAuth()}}};init_browser_manager();var log8=getDomainLogger("project",{component:"domain"}),Project3=class{constructor(e,t,i){if(__publicField(this,"metadata"),__publicField(this,"projectPath"),__publicField(this,"config",null),__publicField(this,"fileSystemRepo"),this.projectPath=e,this.metadata=t,this.fileSystemRepo=i,!this.fileSystemRepo)throw new Error("FileSystemRepository is required for Project")}getPath(){return this.projectPath}getMetadata(){return this.metadata}getId(){return this.metadata.id}getName(){return this.metadata.name}getWorkspaceId(){return this.metadata.workspaceId}getBuildHistory(){return this.metadata.buildHistory||[]}addBuildHistory(e){const t=[e,...this.metadata.buildHistory||[]],i=t.length>50?t.slice(0,50):t;this.metadata=this.metadata.update({buildHistory:i}),log8.debug(`Added build history entry for project: ${this.metadata.name}`)}getLastBuildTime(){const e=this.getBuildHistory();return e.length>0?e[0].timestamp:void 0}updateName(e){this.metadata=this.metadata.update({name:e})}async loadConfig(){if(this.config)return this.config;try{const e=this.fileSystemRepo.join(this.projectPath,"config.json"),t=await this.fileSystemRepo.readFile(e,"utf-8");return this.config=JSON.parse(t),this.config}catch(e){return log8.warn(`Failed to load config for project ${this.metadata.name}, using defaults`),this.config={contentDir:"content",publishDir:"public",defaultContentLanguage:"zh"},this.config}}getConfig(){return this.config}async getContentDirs(){const e=await this.loadConfig(),t=[],i=e.contentDir||"content";if(t.push(this.fileSystemRepo.join(this.projectPath,i)),e.languages)for(const[s,r]of Object.entries(e.languages))r.contentDir&&r.contentDir!==i&&t.push(this.fileSystemRepo.join(this.projectPath,r.contentDir));return[...new Set(t)]}async getPublishDir(){const e=(await this.loadConfig()).publishDir||"public";return this.fileSystemRepo.join(this.projectPath,e)}getStaticDir(){return this.fileSystemRepo.join(this.projectPath,"static")}async getDefaultLanguage(){return(await this.loadConfig()).defaultContentLanguage||"zh"}async getLanguages(){const e=await this.loadConfig();return e.languages?Object.keys(e.languages):[await this.getDefaultLanguage()]}getConfigPath(){return this.fileSystemRepo.join(this.projectPath,"config.json")}getConfigValue(e){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");return this.getNestedValue(this.config,e)}setConfigValue(e,t){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");this.setNestedValue(this.config,e,t),log8.debug(`Project config updated: ${e}`,{projectName:this.metadata.name})}setConfig(e){if(null===this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");this.config=e,log8.debug("Project config replaced entirely",{projectName:this.metadata.name})}unsetConfigValue(e){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");const t=this.deleteNestedValue(this.config,e);return t&&log8.debug(`Project config deleted: ${e}`,{projectName:this.metadata.name}),t}async saveConfig(){if(!this.config)throw new Error("Configuration not loaded. Call loadConfig() first.");const e=this.getConfigPath();await this.fileSystemRepo.writeFile(e,JSON.stringify(this.config,null,2),"utf-8"),log8.debug(`Project config saved: ${e}`,{projectName:this.metadata.name})}getNestedValue(e,t){const i=t.split(".");let s=e;for(const e of i){if(null==s||"object"!=typeof s)return;s=s[e]}return s}setNestedValue(e,t,i){const s=t.split(".");let r=e;for(let e=0;e<s.length-1;e++){const t=s[e];t in r&&"object"==typeof r[t]&&!Array.isArray(r[t])||(r[t]={}),r=r[t]}r[s[s.length-1]]=i}deleteNestedValue(e,t){const i=t.split(".");let s=e;for(let e=0;e<i.length-1;e++){const t=i[e];if(!(t in s)||"object"!=typeof s[t])return!1;s=s[t]}const r=i[i.length-1];return r in s&&(delete s[r],!0)}getInfo(){const e=this.getLastBuildTime(),t={id:this.metadata.id,name:this.metadata.name,path:this.projectPath,createdAt:new Date(this.metadata.createdAt),updatedAt:new Date(this.metadata.updatedAt),buildCount:this.getBuildHistory().length};return e&&(t.lastBuild=new Date(e)),t}getSnapshotsDir(){return this.fileSystemRepo.join(this.projectPath,".mdfriday","snapshots")}hasSourceLinks(){return this.metadata.contentLinks.length>0||null!==this.metadata.staticLink}getContentLinks(){return[...this.metadata.contentLinks]}getStaticLink(){return this.metadata.staticLink?{...this.metadata.staticLink}:null}getFileLink(){return this.metadata.fileLink?{...this.metadata.fileLink}:null}setContentLinks(e){this.metadata=this.metadata.update({contentLinks:e}),log8.debug(`Updated content links for project: ${this.metadata.name}`,{count:e.length})}setStaticLink(e){this.metadata=this.metadata.update({staticLink:e}),log8.debug(`Updated static link for project: ${this.metadata.name}`,{hasLink:null!==e})}addContentLink(e,t,i){const s=[...this.getContentLinks(),{sourcePath:e,languageCode:t,weight:i}];this.setContentLinks(s)}getDefaultContentSource(){const e=this.metadata.contentLinks.find(e=>0===e.weight);return e?e.sourcePath:null}getAllContentSources(){return this.metadata.contentLinks.map(e=>e.sourcePath)}getContentSourceByLanguage(e){const t=this.metadata.contentLinks.find(t=>t.languageCode===e);return t?t.sourcePath:null}getSupportedLanguagesFromLinks(){return this.metadata.contentLinks.map(e=>e.languageCode)}isLinkedProject(){return this.hasSourceLinks()}getLinkDirs(){const e=[],t=this.getFileLink();t&&e.push(t.sourcePath);const i=this.getContentLinks();for(const t of i)e.includes(t.sourcePath)||e.push(t.sourcePath);return e}async getBaseURL(){return(await this.loadConfig()).baseURL||"/"}async setBaseURL(e){const t=await this.loadConfig();t.baseURL=e;const i=this.fileSystemRepo.join(this.projectPath,"config.json");await this.fileSystemRepo.writeFile(i,JSON.stringify(t,null,2),"utf-8"),this.config=t}parseBaseURLPath(e){let t=e.trim();if(t.startsWith("/")&&(t=t.slice(1)),t.endsWith("/")&&(t=t.slice(0,-1)),""===t)return{isRoot:!0,pathParts:[],parentParts:[],finalDirName:"",relativeToPublic:"."};const i=t.split("/").filter(e=>""!==e);if(0===i.length)return{isRoot:!0,pathParts:[],parentParts:[],finalDirName:"",relativeToPublic:"."};const s=i.length,r=1===s?".":"../".repeat(s-1).slice(0,-1);return{isRoot:!1,pathParts:i,parentParts:i.slice(0,-1),finalDirName:i[i.length-1],relativeToPublic:r}}getBaseURLStructure(){return this.metadata.baseURLStructure||null}updateBaseURLStructure(e){this.metadata=this.metadata.update({baseURLStructure:e})}};init_browser_manager(),getDomainLogger("workspace-auth",{component:"domain"});var Authentication2=class{constructor(e,t=!1){__publicField(this,"workspacePath"),__publicField(this,"hasAuthFile",!1),this.workspacePath=e,this.hasAuthFile=t}getWorkspacePath(){return this.workspacePath}hasAuth(){return this.hasAuthFile}markAuthExists(){this.hasAuthFile=!0}markAuthDeleted(){this.hasAuthFile=!1}getAuthFilePath(){return".mdfriday/auth-user.json"}getServerConfigPath(){return".mdfriday/server-config.json"}};init_project_metadata(),init_browser_manager();var log10=getDomainLogger("workspace-factory",{component:"domain"});function generateProjectId(e){return`${e.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"")}-${Date.now().toString(36)}`}var WorkspaceFactory2=class{constructor(e){if(__publicField(this,"workspaceRepo"),__publicField(this,"projectRepo"),__publicField(this,"snapshotRepo"),__publicField(this,"fileSystemRepo"),this.workspaceRepo=e.workspaceRepo,this.projectRepo=e.projectRepo,this.snapshotRepo=e.snapshotRepo,this.fileSystemRepo=e.fileSystemRepo,!this.fileSystemRepo)throw new Error("FileSystemRepository is required")}async load(e){const t=this.fileSystemRepo.resolvePathSync(e);log10.info("Loading workspace",{path:t});const i=await this.workspaceRepo.loadWorkspaceMetadata(t),s=WorkspaceMetadata.create(i),r=await this.workspaceRepo.loadProjectRegistry(t),a=new Map;for(const e of r.projects)try{const t=await this.projectRepo.loadProjectMetadata(e.absolutePath),i=ProjectMetadata.create(t),s=new Project3(e.absolutePath,i,this.fileSystemRepo);a.set(e.id,s),log10.debug("Project loaded",{projectId:e.id,name:e.name})}catch(t){log10.warn("Failed to load project, skipping",{projectId:e.id,path:e.absolutePath,error:t.message})}const n=await this.checkAuthFile(t),o=new Authentication2(t,n),c=new Workspace2(t,s,a,o,this.fileSystemRepo);return log10.info("Workspace loaded",{workspaceId:c.getId(),name:c.getName(),projectCount:c.getProjectCount()}),c}async checkAuthFile(e){const t=this.fileSystemRepo.join(e,".mdfriday","auth-token.json");try{return await this.fileSystemRepo.access(t),!0}catch{return!1}}async create(e,t={}){const i=this.fileSystemRepo.resolvePathSync(e);if(log10.info("Creating workspace",{path:i}),await this.workspaceRepo.isWorkspace(i))throw new Error(`Workspace already exists at ${i}`);const s=t.modulesDir||"modules",r=t.projectsDir||"projects";await this.workspaceRepo.initWorkspaceStructure(i,s,r);const a=Date.now(),n=WorkspaceMetadata.create({version:"1.0",id:`workspace-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,name:t.name||this.fileSystemRepo.basename(i),createdAt:a,updatedAt:a,paths:{modules:s,projects:r},defaults:{modulesDir:s,language:"en"}});await this.workspaceRepo.saveWorkspaceMetadata(i,n.toJSON()),await this.workspaceRepo.saveProjectRegistry(i,{version:"1.0",projects:[]});const o=this.fileSystemRepo.join(i,".mdfriday"),c=this.fileSystemRepo.join(o,"config.json");await this.fileSystemRepo.writeFile(c,"{}","utf-8");const l=this.fileSystemRepo.join(o,"user-data.json");await this.fileSystemRepo.writeFile(l,"{}","utf-8"),log10.debug("Initialized configuration files",{configPath:c,userDataPath:l});const u=new Authentication2(i,!1),d=new Workspace2(i,n,new Map,u,this.fileSystemRepo);return log10.info("Workspace created",{workspaceId:d.getId(),name:d.getName()}),d}async save(e){const t=e.getPath();log10.info("Saving workspace",{workspaceId:e.getId(),path:t}),await this.workspaceRepo.saveWorkspaceMetadata(t,e.getMetadata().toJSON());const i=e.getProjectRegistry();await this.workspaceRepo.saveProjectRegistry(t,i);for(const t of e.getProjects())await this.projectRepo.saveProjectMetadata(t.getPath(),t.getMetadata().toJSON());log10.info("Workspace saved",{workspaceId:e.getId(),projectCount:e.getProjectCount()})}async findWorkspaceRoot(e){let t=this.fileSystemRepo.resolvePathSync(e);const i=this.fileSystemRepo.parsePath(t).root;for(;t!==i;){if(await this.workspaceRepo.isWorkspace(t))return t;t=this.fileSystemRepo.dirname(t)}return null}async isWorkspace(e){const t=this.fileSystemRepo.resolvePathSync(e);return this.workspaceRepo.isWorkspace(t)}async loadOrFind(e){const t=e||process.cwd(),i=await this.findWorkspaceRoot(t);if(!i)throw new Error('No workspace found. Run "mdf workspace init" to create one.');return this.load(i)}async createProject(e,t,i={}){const s=generateProjectId(t),r=this.fileSystemRepo.join(e.getProjectsDir(),t);if(log10.info("Creating project",{projectId:s,name:t,path:r}),e.findProject(t))throw new Error(`Project ${t} already exists`);const a=i.contentDir||"content",n=i.staticDir||"static",o=i.publishDir||"public";await this.projectRepo.initProjectStructure(r,a,n,o);const c=Date.now(),l=ProjectMetadata.create({id:s,name:t,workspaceId:e.getId(),createdAt:c,updatedAt:c}),u=i.theme||"https://gohugo.net/quartz-theme.zip?version=1.2",d={baseURL:i.baseURL||"/",title:t,contentDir:a,publishDir:o,defaultContentLanguage:i.language||"en",module:{imports:[{path:u}]}};await this.projectRepo.saveProjectMetadata(r,l.toJSON()),await this.projectRepo.saveProjectConfig(r,d);const h=this.fileSystemRepo.join(r,a,"index.md");await this.projectRepo.createSampleContent(h,this.createSampleContent());const g=new Project3(r,l,this.fileSystemRepo);return e.addProject(g),await this.save(e),log10.info("Project created",{projectId:s,name:t}),g}async deleteProject(e,t,i={}){const s=e.findProject(t);if(!s)throw new Error(`Project not found: ${t}`);log10.info("Deleting project",{projectId:s.getId(),name:s.getName(),deleteFiles:i.deleteFiles}),e.removeProject(s.getId()),await this.save(e),i.deleteFiles&&(await this.projectRepo.deleteProjectFiles(s.getPath()),log10.info("Project files deleted",{projectId:s.getId()})),log10.info("Project deleted",{projectId:s.getId(),name:s.getName()})}async createProjectFromFolder(e,t,i,s={}){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to create project from folder");const r=generateProjectId(t),a=this.fileSystemRepo.join(e.getProjectsDir(),t);if(log10.info("Creating project from folder",{projectId:r,name:t,sourcePath:i,targetPath:a}),e.findProject(t))throw new Error(`Project ${t} already exists`);const n=await this.fileSystemRepo.scanFolderStructure(i),o=FolderStructure.fromScanResult(n);let c;log10.debug("Scanned folder structure",{isStructured:o.getIsStructured(),contentFolders:o.getContentFolderCount(),hasStatic:o.hasStaticFolder()}),o.getIsStructured()&&0!==o.getContentFolderCount()?c=o:(log10.info("No standard structure found, treating source folder as content directory"),c=FolderStructure.createSingleContent(i,i,s.language||"en")),await this.projectRepo.initProjectStructure(a,"content","static","public");const l=[],u=[];for(const e of c.getContentFolders()){const t=0===e.weight?this.fileSystemRepo.join(a,"content"):this.fileSystemRepo.join(a,`content.${e.languageCode}`);l.push({source:e.path,target:t}),u.push({sourcePath:e.path,languageCode:e.languageCode,weight:e.weight})}let d=null;if(c.hasStaticFolder()){const e=c.getStaticFolder();l.push({source:e.path,target:this.fileSystemRepo.join(a,"static")}),d={sourcePath:e.path}}const h=(await this.fileSystemRepo.createSymlinks(l)).filter(e=>!e.success);if(h.length>0)throw log10.error("Some symlinks failed to create",{failed:h}),new Error(`Failed to create symlinks: ${h.map(e=>e.error).join(", ")}`);const g=Date.now(),p=ProjectMetadata.create({id:r,name:t,workspaceId:e.getId(),createdAt:g,updatedAt:g,contentLinks:u,staticLink:d}),f=s.theme||"https://gohugo.net/quartz-theme.zip?version=1.2",m={baseURL:"/",title:t,contentDir:"content",publishDir:"public",defaultContentLanguage:c.getDefaultContentFolder()?.languageCode||s.language||"en",module:{imports:[{path:f}]}};if(c.hasContentFolders()){const e={};for(const t of c.getContentFolders()){const i=0===t.weight?"content":`content.${t.languageCode}`;e[t.languageCode]={contentDir:i,weight:t.weight+1}}m.languages=e}await this.projectRepo.saveProjectMetadata(a,p.toJSON()),await this.projectRepo.saveProjectConfig(a,m);const y=new Project3(a,p,this.fileSystemRepo);return e.addProject(y),await this.save(e),log10.info("Project created from folder",{projectId:r,name:t,linkedContentFolders:u.length,hasStaticLink:null!==d}),y}async createProjectFromFile(e,t,i,s={}){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to create project from file");const r=generateProjectId(t),a=this.fileSystemRepo.join(e.getProjectsDir(),t);if(log10.info("Creating project from file",{projectId:r,name:t,sourceFile:i,targetPath:a}),e.findProject(t))throw new Error(`Project ${t} already exists`);if(!await this.fileSystemRepo.exists(i))throw new Error(`Source file not found: ${i}`);if(!(await this.fileSystemRepo.stat(i)).isFile())throw new Error(`Source path is not a file: ${i}`);await this.projectRepo.initProjectStructure(a,"content","static","public");const n=this.fileSystemRepo.join(a,"content"),o=this.fileSystemRepo.join(n,"index.md");let c=!1,l=null;try{await this.fileSystemRepo.exists(n)&&await this.fileSystemRepo.remove(n,!0),await this.fileSystemRepo.createDirectory(n,!0);const e=await this.fileSystemRepo.createSymlink(i,o);if(!e.success)throw new Error(e.error||"Failed to create symlink");c=!0,l={source:i,target:o},log10.info("Created symlink for file",{source:i,target:o})}catch(e){log10.warn("Symlink creation failed, falling back to file copy",{error:e});try{await this.fileSystemRepo.copyFile(i,o),log10.info("Copied file as fallback",{source:i,target:o})}catch(e){throw log10.error("Failed to copy file",e),new Error(`Failed to create file link or copy: ${e.message}`)}}const u=Date.now(),d=ProjectMetadata.create({id:r,name:t,workspaceId:e.getId(),createdAt:u,updatedAt:u,fileLink:l?{sourcePath:l.source,targetPath:l.target,isSymlink:c}:null}),h=s.theme||"https://gohugo.net/note.zip?version=1.2",g={baseURL:"/",title:t,contentDir:"content",publishDir:"public",defaultContentLanguage:s.language||"en",module:{imports:[{path:h}]}};await this.projectRepo.saveProjectMetadata(a,d.toJSON()),await this.projectRepo.saveProjectConfig(a,g);const p=new Project3(a,d,this.fileSystemRepo);return e.addProject(p),await this.save(e),log10.info("Project created from file",{projectId:r,name:t,sourceFile:i,useSymlink:c}),p}async loadProject(e){const t=this.fileSystemRepo.resolvePathSync(e);if(!await this.projectRepo.isProject(t))throw new Error(`No project found at ${t}`);const i=await this.projectRepo.loadProjectMetadata(t),{ProjectMetadata:s}=await Promise.resolve().then(()=>(init_project_metadata(),project_metadata_exports)),r=s.create(i);return new Project3(t,r,this.fileSystemRepo)}async saveProject(e){const t=e.getPath();await this.projectRepo.saveProjectMetadata(t,e.getMetadata().toJSON()),e.getConfig()&&await e.saveConfig(),log10.debug(`Saved project: ${e.getName()}`)}async findProjectRoot(e){let t=this.fileSystemRepo.resolvePathSync(e);const i=this.fileSystemRepo.parsePath(t).root;for(;t!==i;){if(await this.projectRepo.isProject(t))return t;t=this.fileSystemRepo.dirname(t)}return null}async createSnapshot(e,t){const i=e.getPath(),s=await e.getPublishDir(),r=`${(new Date).toISOString().replace(/[:.]/g,"-").split(".")[0]}Z`;log10.info("Creating snapshot",{projectId:e.getId(),snapshotId:r});const a=await this.snapshotRepo.createSnapshot(i,r,s);if(t&&t!==a.id){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to update snapshot metadata");a.name=t;const i=this.fileSystemRepo.join(e.getPath(),".mdfriday","snapshots",`${a.id}.json`);await this.fileSystemRepo.writeFile(i,JSON.stringify(a,null,2))}return log10.info("Snapshot created",{snapshotId:r,size:a.size,fileCount:a.fileCount}),a}async listSnapshots(e){return(await this.snapshotRepo.listSnapshots(e.getPath())).sort((e,t)=>t.timestamp-e.timestamp)}async restoreSnapshot(e,t,i){const s=i||await e.getPublishDir();await this.snapshotRepo.restoreSnapshot(e.getPath(),t,s)}async deleteSnapshot(e,t){await this.snapshotRepo.deleteSnapshot(e.getPath(),t)}async getSnapshot(e,t){return await this.snapshotRepo.getSnapshot(e.getPath(),t)}createIdentityStorage(e){const t=e.getPath(),i=e.getAuthentication(),s=this.fileSystemRepo;if(!s)throw new Error("FileSystemRepository is required for identity storage");return{async saveUserData(e){const r=s.join(t,".mdfriday","user-data.json");await s.createDirectory(s.dirname(r),!0);const a={};e.serverConfig&&(a.serverConfig=e.serverConfig.toJSON()),e.token&&(a.token=e.token.toJSON(),i.markAuthExists()),e.license&&(a.license=e.license.toJSON()),e.syncConfig&&(a.syncConfig=e.syncConfig.toJSON()),e.email&&(a.email=e.email),await s.writeFile(r,JSON.stringify(a,null,2))},async loadUserData(){const e=s.join(t,".mdfriday","user-data.json");try{const t=await s.readFile(e,"utf-8"),i=JSON.parse(t),{Token:r,ServerConfig:a,License:n,SyncConfig:o}=await Promise.resolve().then(()=>(init_identity(),identity_exports)),c={};return i.serverConfig&&(c.serverConfig=a.create(i.serverConfig.apiUrl,i.serverConfig.websiteUrl)),i.token&&(c.token=r.create(i.token.token||i.token.value,i.token.expiresAt)),i.license&&(c.license=n.create(i.license.key,i.license.plan,i.license.expiresAt,i.license.features,i.license.activatedAt,i.license.activated,i.license.firstTime)),i.syncConfig&&(c.syncConfig=o.fromJSON(i.syncConfig)),i.email&&(c.email=i.email),c}catch{return null}},async clearUserData(){const e=s.join(t,".mdfriday","user-data.json");try{await s.unlink(e)}catch{}i.markAuthDeleted()}}}async setupBaseURLStructure(e){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required for baseURL structure");const t=await e.getBaseURL(),i=e.parseBaseURLPath(t),s=e.getPath(),r=this.fileSystemRepo.join(s,"public");if(i.isRoot)return log10.debug("baseURL is root, no structure needed"),{serverRoot:r,baseURL:"/",symlinkCreated:!1};log10.info("Creating baseURL structure in public/",{baseURL:t,pathParts:i.pathParts});let a=r;for(const e of i.parentParts)a=this.fileSystemRepo.join(a,e),await this.fileSystemRepo.exists(a)||(await this.fileSystemRepo.createDirectory(a,!1),log10.debug(`Created parent directory: ${e}`));const n=this.fileSystemRepo.join(a,i.finalDirName);await this.fileSystemRepo.exists(n)&&(await this.fileSystemRepo.remove(n,!0),log10.debug(`Removed existing symlink: ${n}`));const o=await this.fileSystemRepo.createSymlink(i.relativeToPublic,n);if(!o.success)throw log10.error("Failed to create baseURL symlink",{target:i.relativeToPublic,link:n,error:o.error}),new Error(`Failed to create baseURL structure: ${o.error}`);return log10.info("baseURL structure created successfully",{symlinkPath:i.pathParts.join("/"),target:i.relativeToPublic}),e.updateBaseURLStructure({baseURL:t,createdAt:Date.now(),pathParts:i.pathParts}),await this.projectRepo.saveProjectMetadata(e.getPath(),e.getMetadata().toJSON()),{serverRoot:r,baseURL:t,symlinkCreated:!0}}async cleanBaseURLStructure(e){if(!this.fileSystemRepo)return;const t=e.getBaseURLStructure();if(!t||0===t.pathParts.length)return;const i=e.getPath(),s=this.fileSystemRepo.join(i,"public");log10.info("Cleaning baseURL structure in public/",{pathParts:t.pathParts});for(let e=t.pathParts.length;e>0;e--){const i=this.fileSystemRepo.join(s,...t.pathParts.slice(0,e));if(await this.fileSystemRepo.exists(i)&&(await this.fileSystemRepo.remove(i,!0),log10.debug(`Removed: ${t.pathParts.slice(0,e).join("/")}`)),e>1){const i=this.fileSystemRepo.join(s,...t.pathParts.slice(0,e-1));if(await this.fileSystemRepo.exists(i)&&(await this.fileSystemRepo.readDirectory(i)).length>0)break}}e.updateBaseURLStructure(null),await this.projectRepo.saveProjectMetadata(e.getPath(),e.getMetadata().toJSON()),log10.info("baseURL structure cleaned")}async ensureBaseURLStructure(e){const t=await e.getBaseURL(),i=e.getBaseURLStructure();return i&&i.baseURL===t?{serverRoot:this.fileSystemRepo.join(e.getPath(),"public"),baseURL:t,recreated:!1}:(i&&(log10.info("baseURL changed, recreating structure",{old:i.baseURL,new:t}),await this.cleanBaseURLStructure(e)),{...await this.setupBaseURLStructure(e),recreated:!0})}async scanFolderStructure(e){if(!this.fileSystemRepo)throw new Error("FileSystemRepository is required to scan folder structure");log10.info("Scanning folder structure",{path:e});const t=await this.fileSystemRepo.scanFolderStructure(e),i=FolderStructure.fromScanResult(t);return log10.debug("Folder structure scanned",{isStructured:i.getIsStructured(),contentFolders:i.getContentFolderCount(),hasStatic:i.hasStaticFolder(),languages:i.getSupportedLanguages()}),i}createSampleContent(){return`---\ntitle: Welcome to MDFriday\ndate: ${(new Date).toISOString()}\n---\n\n# Welcome to MDFriday\n\nThis is a sample page. Edit this file to get started!\n\n## Features\n\n- **Markdown Support**: Write content in Markdown\n- **Themes**: Beautiful themes out of the box\n- **Fast**: Static site generation for speed\n- **Flexible**: Customize everything\n\n## Getting Started\n\n1. Edit files in the \`content/\` directory\n2. Run \`mdf serve\` to preview\n3. Run \`mdf build\` to generate your site\n`}};function createObsidianWorkspaceAppService(e){if(!e)throw new Error("[Foundry Mobile] Configuration is required for Mobile environment. Please provide ObsidianMobileEnvironmentConfig with workspace and fileSystem repositories. See: docs/obsidian-mobile-implementation.md");const t=new WorkspaceFactory2({workspaceRepo:e.persistence.workspace,projectRepo:e.persistence.workspace,snapshotRepo:e.persistence.workspace,fileSystemRepo:e.persistence.fileSystem});return new WorkspaceAppService({workspaceFactory:t})}async function createObsidianIdentityService(e,t,i){if(!i)throw new Error("[Foundry Mobile] Configuration is required for Mobile environment. Please provide ObsidianMobileEnvironmentConfig. See: docs/obsidian-mobile-implementation.md");const s=createObsidianWorkspaceAppService(i),r=i?i.identityHttpClient:t,a=await s.loadWorkspace(e),n=s.createIdentityStorage(a),o=new UserFactory({httpClient:r,storageProvider:n}),c=new IdentityAppService({userFactory:o});return await c.initialize(),c}init_project_metadata(),init_identity();var MobileIdentityAdapter=class{constructor(e){this.config=e}async getIdentityService(e,t){return await createObsidianIdentityService(e,t,this.config)}},MobileWorkspaceAdapter=class{constructor(e){this.config=e,__publicField(this,"workspaceAppService")}getWorkspaceAppService(){return this.workspaceAppService||(this.workspaceAppService=createObsidianWorkspaceAppService(this.config)),this.workspaceAppService}getWorkspaceFactory(){return this.getWorkspaceAppService().workspaceFactory}getFileSystemRepository(){return this.config.persistence.fileSystem}};function createObsidianWorkspaceService(e){const t=new MobileWorkspaceAdapter(e);return new ObsidianWorkspaceService(t)}function createObsidianAuthService(e,t){const i=new MobileIdentityAdapter(t);return new ObsidianAuthService(e,i)}function createObsidianLicenseService(e,t){const i=new MobileIdentityAdapter(t);return new ObsidianLicenseService(e,i)}function createObsidianGlobalConfigService(e){const t=new MobileWorkspaceAdapter(e);return new ObsidianGlobalConfigService(t)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mdfriday/foundry",
3
- "version": "26.4.14",
3
+ "version": "26.4.15",
4
4
  "description": "The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",